From 2a1127622dbdf05e471366cb57ec749dcd6d155a Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Fri, 25 Dec 2020 16:56:02 +0200 Subject: [PATCH] feat(cdk/a11y): add input to control the duration of the aria live directive 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; }