@react-aria/live-announcer
Version:
Spectrum UI components in React
113 lines (110 loc) • 6.32 kB
JavaScript
/*
* Copyright 2020 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/ /* Inspired by https://github.com/AlmeroSteyn/react-aria-live */ const $319e236875307eab$var$LIVEREGION_TIMEOUT_DELAY = 7000;
let $319e236875307eab$var$liveAnnouncer = null;
function $319e236875307eab$export$a9b970dcc4ae71a9(message, assertiveness = 'assertive', timeout = $319e236875307eab$var$LIVEREGION_TIMEOUT_DELAY) {
if (!$319e236875307eab$var$liveAnnouncer) {
$319e236875307eab$var$liveAnnouncer = new $319e236875307eab$var$LiveAnnouncer();
// wait for the live announcer regions to be added to the dom, then announce
// otherwise Safari won't announce the message if it's added too quickly
// found most times less than 100ms were not consistent when announcing with Safari
// IS_REACT_ACT_ENVIRONMENT is used by React 18. Previous versions checked for the `jest` global.
// https://github.com/reactwg/react-18/discussions/102
// if we're in a test environment, announce without waiting
// @ts-ignore
if (!(typeof IS_REACT_ACT_ENVIRONMENT === 'boolean' ? IS_REACT_ACT_ENVIRONMENT : typeof jest !== 'undefined')) setTimeout(()=>{
if ($319e236875307eab$var$liveAnnouncer === null || $319e236875307eab$var$liveAnnouncer === void 0 ? void 0 : $319e236875307eab$var$liveAnnouncer.isAttached()) $319e236875307eab$var$liveAnnouncer === null || $319e236875307eab$var$liveAnnouncer === void 0 ? void 0 : $319e236875307eab$var$liveAnnouncer.announce(message, assertiveness, timeout);
}, 100);
else $319e236875307eab$var$liveAnnouncer.announce(message, assertiveness, timeout);
} else $319e236875307eab$var$liveAnnouncer.announce(message, assertiveness, timeout);
}
function $319e236875307eab$export$d10ae4f68404609a(assertiveness) {
if ($319e236875307eab$var$liveAnnouncer) $319e236875307eab$var$liveAnnouncer.clear(assertiveness);
}
function $319e236875307eab$export$d8686216b8b81b2f() {
if ($319e236875307eab$var$liveAnnouncer) {
$319e236875307eab$var$liveAnnouncer.destroy();
$319e236875307eab$var$liveAnnouncer = null;
}
}
// LiveAnnouncer is implemented using vanilla DOM, not React. That's because as of React 18
// ReactDOM.render is deprecated, and the replacement, ReactDOM.createRoot is moved into a
// subpath import `react-dom/client`. That makes it hard for us to support multiple React versions.
// As a global API, we can't use portals without introducing a breaking API change. LiveAnnouncer
// is simple enough to implement without React, so that's what we do here.
// See this discussion for more details: https://github.com/reactwg/react-18/discussions/125#discussioncomment-2382638
class $319e236875307eab$var$LiveAnnouncer {
isAttached() {
var _this_node;
return (_this_node = this.node) === null || _this_node === void 0 ? void 0 : _this_node.isConnected;
}
createLog(ariaLive) {
let node = document.createElement('div');
node.setAttribute('role', 'log');
node.setAttribute('aria-live', ariaLive);
node.setAttribute('aria-relevant', 'additions');
return node;
}
destroy() {
if (!this.node) return;
document.body.removeChild(this.node);
this.node = null;
}
announce(message, assertiveness = 'assertive', timeout = $319e236875307eab$var$LIVEREGION_TIMEOUT_DELAY) {
var _this_assertiveLog, _this_politeLog;
if (!this.node) return;
let node = document.createElement('div');
if (typeof message === 'object') {
// To read an aria-labelledby, the element must have an appropriate role, such as img.
node.setAttribute('role', 'img');
node.setAttribute('aria-labelledby', message['aria-labelledby']);
} else node.textContent = message;
if (assertiveness === 'assertive') (_this_assertiveLog = this.assertiveLog) === null || _this_assertiveLog === void 0 ? void 0 : _this_assertiveLog.appendChild(node);
else (_this_politeLog = this.politeLog) === null || _this_politeLog === void 0 ? void 0 : _this_politeLog.appendChild(node);
if (message !== '') setTimeout(()=>{
node.remove();
}, timeout);
}
clear(assertiveness) {
if (!this.node) return;
if ((!assertiveness || assertiveness === 'assertive') && this.assertiveLog) this.assertiveLog.innerHTML = '';
if ((!assertiveness || assertiveness === 'polite') && this.politeLog) this.politeLog.innerHTML = '';
}
constructor(){
this.node = null;
this.assertiveLog = null;
this.politeLog = null;
if (typeof document !== 'undefined') {
this.node = document.createElement('div');
this.node.dataset.liveAnnouncer = 'true';
// copied from VisuallyHidden
Object.assign(this.node.style, {
border: 0,
clip: 'rect(0 0 0 0)',
clipPath: 'inset(50%)',
height: '1px',
margin: '-1px',
overflow: 'hidden',
padding: 0,
position: 'absolute',
width: '1px',
whiteSpace: 'nowrap'
});
this.assertiveLog = this.createLog('assertive');
this.node.appendChild(this.assertiveLog);
this.politeLog = this.createLog('polite');
this.node.appendChild(this.politeLog);
document.body.prepend(this.node);
}
}
}
export {$319e236875307eab$export$a9b970dcc4ae71a9 as announce, $319e236875307eab$export$d10ae4f68404609a as clearAnnouncer, $319e236875307eab$export$d8686216b8b81b2f as destroyAnnouncer};
//# sourceMappingURL=LiveAnnouncer.module.js.map