mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(snack-bar): set appropriate role based on passed in politeness (#13864)
Currently we always have a `role` of `alert` on the snack bar container which has an implicit politeness of `assertive` and which can override the message announced by the live announcer. These changes set the role to `status` if it's set to `polite` or remove the role completely if the politeness is turned off. Fixes #13493.
This commit is contained in:
committed by
Jeremy Elbourn
parent
99d2512888
commit
50f999b5e5
@@ -44,7 +44,7 @@ import {MatSnackBarConfig} from './snack-bar-config';
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
animations: [matSnackBarAnimations.snackBarState],
|
||||
host: {
|
||||
'role': 'alert',
|
||||
'[attr.role]': '_role',
|
||||
'class': 'mat-snack-bar-container',
|
||||
'[@state]': '_animationState',
|
||||
'(@state.done)': 'onAnimationEnd($event)'
|
||||
@@ -66,6 +66,9 @@ export class MatSnackBarContainer extends BasePortalOutlet implements OnDestroy
|
||||
/** The state of the snack bar animations. */
|
||||
_animationState = 'void';
|
||||
|
||||
/** ARIA role for the snack bar container. */
|
||||
_role: 'alert' | 'status' | null;
|
||||
|
||||
constructor(
|
||||
private _ngZone: NgZone,
|
||||
private _elementRef: ElementRef<HTMLElement>,
|
||||
@@ -74,6 +77,16 @@ export class MatSnackBarContainer extends BasePortalOutlet implements OnDestroy
|
||||
public snackBarConfig: MatSnackBarConfig) {
|
||||
|
||||
super();
|
||||
|
||||
// Based on the ARIA spec, `alert` and `status` roles have an
|
||||
// implicit `assertive` and `polite` politeness respectively.
|
||||
if (snackBarConfig.politeness === 'assertive') {
|
||||
this._role = 'alert';
|
||||
} else if (snackBarConfig.politeness === 'polite') {
|
||||
this._role = 'status';
|
||||
} else {
|
||||
this._role = null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Attach a component portal as content to this snack bar container. */
|
||||
|
||||
@@ -67,13 +67,31 @@ describe('MatSnackBar', () => {
|
||||
testViewContainerRef = viewContainerFixture.componentInstance.childViewContainer;
|
||||
});
|
||||
|
||||
it('should have the role of alert', () => {
|
||||
snackBar.open(simpleMessage, simpleActionLabel);
|
||||
it('should have the role of `alert` with an `assertive` politeness', () => {
|
||||
snackBar.open(simpleMessage, simpleActionLabel, {politeness: 'assertive'});
|
||||
viewContainerFixture.detectChanges();
|
||||
|
||||
let containerElement = overlayContainerElement.querySelector('snack-bar-container')!;
|
||||
const containerElement = overlayContainerElement.querySelector('snack-bar-container')!;
|
||||
expect(containerElement.getAttribute('role'))
|
||||
.toBe('alert', 'Expected snack bar container to have role="alert"');
|
||||
});
|
||||
});
|
||||
|
||||
it('should have the role of `status` with a `polite` politeness', () => {
|
||||
snackBar.open(simpleMessage, simpleActionLabel, {politeness: 'polite'});
|
||||
viewContainerFixture.detectChanges();
|
||||
|
||||
const containerElement = overlayContainerElement.querySelector('snack-bar-container')!;
|
||||
expect(containerElement.getAttribute('role'))
|
||||
.toBe('status', 'Expected snack bar container to have role="status"');
|
||||
});
|
||||
|
||||
it('should remove the role if the politeness is turned off', () => {
|
||||
snackBar.open(simpleMessage, simpleActionLabel, {politeness: 'off'});
|
||||
viewContainerFixture.detectChanges();
|
||||
|
||||
const containerElement = overlayContainerElement.querySelector('snack-bar-container')!;
|
||||
expect(containerElement.getAttribute('role')).toBeFalsy('Expected role to be removed');
|
||||
});
|
||||
|
||||
it('should open and close a snackbar without a ViewContainerRef', fakeAsync(() => {
|
||||
let snackBarRef = snackBar.open('Snack time!', 'Chew');
|
||||
|
||||
Reference in New Issue
Block a user