@awsui/components-react
Version:
On July 19th, 2022, we launched [Cloudscape Design System](https://cloudscape.design). Cloudscape is an evolution of AWS-UI. It consists of user interface guidelines, front-end components, design resources, and development tools for building intuitive, en
77 lines • 3.46 kB
JavaScript
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import styles from './styles.css.js';
import testUtilStyles from './test-classes/styles.css.js';
/**
* The controller that manages a single live region container. It has a timer
* to make sure announcements are throttled correctly. It can also make sure
* that a message is announced again even if it matches the previous content
* of the live region.
*
* @see https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions
*/
export class LiveRegionController {
constructor(politeness, delay = LiveRegionController.defaultDelay) {
this.politeness = politeness;
this.delay = delay;
this._addedTerminalPeriod = false;
this._nextAnnouncement = '';
this._element = document.createElement('div');
this._element.className = `${styles.announcer} ${testUtilStyles.announcer}`;
this._element.setAttribute('aria-live', this.politeness);
this._element.setAttribute('aria-atomic', 'true');
document.body.appendChild(this._element);
}
/**
* Reset the state of the controller and clear any active announcements.
*/
destroy() {
var _a;
(_a = this._element) === null || _a === void 0 ? void 0 : _a.remove();
if (this._timeoutId !== undefined) {
clearTimeout(this._timeoutId);
this._timeoutId = undefined;
}
}
announce({ message, forceReannounce = false }) {
if (!message) {
return;
}
this._nextAnnouncement = message.trim();
if (this.delay === 0 || forceReannounce) {
// If the delay is 0, just skip the timeout shenanigans and update the
// element synchronously. Great for tests.
return this._updateElement(forceReannounce);
}
if (this._timeoutId === undefined) {
this._timeoutId = setTimeout(() => this._updateElement(false), this.delay * 1000);
}
}
_updateElement(forceReannounce) {
if (this._nextAnnouncement !== this._lastAnnouncement) {
// The aria-atomic does not work properly in Voice Over, causing
// certain parts of the content to be ignored. To fix that,
// we assign the source text content as a single node.
this._element.textContent = this._nextAnnouncement;
this._addedTerminalPeriod = false;
}
else if (forceReannounce) {
// A (generally) safe way of forcing re-announcements is toggling the
// terminal period. If we only keep adding periods, it's going to be
// eventually interpreted as an ellipsis.
this._element.textContent = this._nextAnnouncement + (this._addedTerminalPeriod ? '' : '.');
this._addedTerminalPeriod = !this._addedTerminalPeriod;
}
// Track the announced text for deduplication.
this._lastAnnouncement = this._nextAnnouncement;
// Reset the state for the next announcement.
this._timeoutId = undefined;
}
}
/**
* The default delay for announcements when no delay is explicitly provided.
* During internal unit testing, you can import this and explicitly set it to
* 0 to make the live region update the DOM without waiting for a timer.
*/
LiveRegionController.defaultDelay = 2;
//# sourceMappingURL=controller.js.map