From 7d0bca7bd39e97ff6b033f97d05a811dfdac25db Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Sat, 26 Feb 2022 17:27:44 +0100 Subject: [PATCH] feat(cdk/a11y): add input to control the duration of the aria live directive (#15275) Adds an input that allows the consumer to control how long it takes before the messages that are announced by `CdkAriaLive` to be cleared from the DOM. --- .../live-announcer/live-announcer.spec.ts | 32 ++++++++++++++----- src/cdk/a11y/live-announcer/live-announcer.ts | 5 ++- tools/public_api_guard/cdk/a11y.md | 3 +- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/cdk/a11y/live-announcer/live-announcer.spec.ts b/src/cdk/a11y/live-announcer/live-announcer.spec.ts index 84b7c1ceab58..accde0d9b5a1 100644 --- a/src/cdk/a11y/live-announcer/live-announcer.spec.ts +++ b/src/cdk/a11y/live-announcer/live-announcer.spec.ts @@ -1,8 +1,8 @@ import {MutationObserverFactory} from '@angular/cdk/observers'; -import {Component, Input} from '@angular/core'; +import {Component} from '@angular/core'; import {ComponentFixture, fakeAsync, flush, inject, TestBed, tick} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; -import {A11yModule, AriaLivePoliteness} from '../index'; +import {A11yModule} from '../index'; import {LiveAnnouncer} from './live-announcer'; import { LIVE_ANNOUNCER_ELEMENT_TOKEN, @@ -280,7 +280,7 @@ describe('CdkAriaLive', () => { invokeMutationCallbacks(); flush(); - expect(announcer.announce).toHaveBeenCalledWith('New content', 'polite'); + expect(announcer.announce).toHaveBeenCalledWith('New content', 'polite', undefined); })); it('should dynamically update the politeness', fakeAsync(() => { @@ -289,7 +289,7 @@ describe('CdkAriaLive', () => { invokeMutationCallbacks(); flush(); - expect(announcer.announce).toHaveBeenCalledWith('New content', 'polite'); + expect(announcer.announce).toHaveBeenCalledWith('New content', 'polite', undefined); announcerSpy.calls.reset(); fixture.componentInstance.politeness = 'off'; @@ -307,7 +307,7 @@ describe('CdkAriaLive', () => { invokeMutationCallbacks(); flush(); - expect(announcer.announce).toHaveBeenCalledWith('Newest content', 'assertive'); + expect(announcer.announce).toHaveBeenCalledWith('Newest content', 'assertive', undefined); })); it('should not announce the same text multiple times', fakeAsync(() => { @@ -324,6 +324,16 @@ describe('CdkAriaLive', () => { expect(announcer.announce).toHaveBeenCalledTimes(1); })); + + it('should be able to pass in a duration', fakeAsync(() => { + fixture.componentInstance.content = 'New content'; + fixture.componentInstance.duration = 1337; + fixture.detectChanges(); + invokeMutationCallbacks(); + flush(); + + expect(announcer.announce).toHaveBeenCalledWith('New content', 'polite', 1337); + })); }); function getLiveElement(): Element { @@ -339,8 +349,14 @@ class TestApp { } } -@Component({template: `
{{content}}
`}) +@Component({ + template: ` +
{{content}}
`, +}) class DivWithCdkAriaLive { - @Input() politeness: AriaLivePoliteness; - @Input() content = 'Initial content'; + politeness = 'polite'; + content = 'Initial content'; + duration: number; } diff --git a/src/cdk/a11y/live-announcer/live-announcer.ts b/src/cdk/a11y/live-announcer/live-announcer.ts index cc78425ade11..4eb584b6993d 100644 --- a/src/cdk/a11y/live-announcer/live-announcer.ts +++ b/src/cdk/a11y/live-announcer/live-announcer.ts @@ -198,7 +198,7 @@ export class CdkAriaLive implements OnDestroy { // The `MutationObserver` fires also for attribute // changes which we don't want to announce. if (elementText !== this._previousAnnouncedText) { - this._liveAnnouncer.announce(elementText, this._politeness); + this._liveAnnouncer.announce(elementText, this._politeness, this.duration); this._previousAnnouncedText = elementText; } }); @@ -207,6 +207,9 @@ export class CdkAriaLive implements OnDestroy { } private _politeness: AriaLivePoliteness = 'polite'; + /** Time in milliseconds after which to clear out the announcer element. */ + @Input('cdkAriaLiveDuration') duration: number; + private _previousAnnouncedText?: string; private _subscription: Subscription | null; diff --git a/tools/public_api_guard/cdk/a11y.md b/tools/public_api_guard/cdk/a11y.md index 44dbf705732f..ac25ff5b7ff1 100644 --- a/tools/public_api_guard/cdk/a11y.md +++ b/tools/public_api_guard/cdk/a11y.md @@ -67,12 +67,13 @@ export const CDK_DESCRIBEDBY_ID_PREFIX = "cdk-describedby-message"; // @public export class CdkAriaLive implements OnDestroy { constructor(_elementRef: ElementRef, _liveAnnouncer: LiveAnnouncer, _contentObserver: ContentObserver, _ngZone: NgZone); + duration: number; // (undocumented) ngOnDestroy(): void; get politeness(): AriaLivePoliteness; set politeness(value: AriaLivePoliteness); // (undocumented) - static ɵdir: i0.ɵɵDirectiveDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration; }