@renderlesskit/react
Version:
Collection of headless components/hooks that are accessible, composable, customizable from low level to build your own UI & Design System powered by Reakit
154 lines (137 loc) • 4.7 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.
*/
import React, { Fragment, useImperativeHandle, useRef, useState } from "react";
import ReactDOM from "react-dom";
import { VisuallyHidden } from "reakit";
/* Inspired by https://github.com/AlmeroSteyn/react-aria-live */
import { jsx as _jsx } from "react/jsx-runtime";
import { jsxs as _jsxs } from "react/jsx-runtime";
var liveRegionAnnouncer = /*#__PURE__*/React.createRef();
var node = null;
var clearTimeoutId = null;
var LIVEREGION_TIMEOUT_DELAY = 1000;
/**
* Announces the message using screen reader technology.
*/
export function announce(message) {
var assertiveness = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "assertive";
var timeout = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : LIVEREGION_TIMEOUT_DELAY;
ensureInstance(announcer => announcer.announce(message, assertiveness, timeout));
}
/**
* Stops all queued announcements.
*/
export function clearAnnouncer(assertiveness) {
ensureInstance(announcer => announcer.clear(assertiveness));
}
/**
* Removes the announcer from the DOM.
*/
export function destroyAnnouncer() {
if (liveRegionAnnouncer.current) {
ReactDOM.unmountComponentAtNode(node);
document.body.removeChild(node);
node = null;
}
}
/**
* Ensures we only have one instance of the announcer so that we don't have elements competing.
*/
function ensureInstance(callback) {
if (!liveRegionAnnouncer.current) {
node = document.createElement("div");
document.body.appendChild(node);
ReactDOM.render( /*#__PURE__*/_jsx(LiveRegionAnnouncer, {
ref: liveRegionAnnouncer
}), node, () => callback(liveRegionAnnouncer.current));
} else {
callback(liveRegionAnnouncer.current);
}
}
export var LiveRegionAnnouncer = /*#__PURE__*/React.forwardRef((props, ref) => {
var [assertiveMessage, setAssertiveMessage] = useState("");
var [politeMessage, setPoliteMessage] = useState("");
var clear = assertiveness => {
if (!assertiveness || assertiveness === "assertive") {
setAssertiveMessage("");
}
if (!assertiveness || assertiveness === "polite") {
setPoliteMessage("");
}
};
var announce = function announce(message) {
var assertiveness = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "assertive";
var timeout = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : LIVEREGION_TIMEOUT_DELAY;
if (clearTimeoutId) {
clearTimeout(clearTimeoutId);
clearTimeoutId = null;
}
if (assertiveness === "assertive") {
setAssertiveMessage(message);
} else {
setPoliteMessage(message);
}
if (message !== "") {
clearTimeoutId = setTimeout(() => {
clear(assertiveness);
}, timeout);
}
};
useImperativeHandle(ref, () => ({
announce,
clear
}));
return /*#__PURE__*/_jsxs(Fragment, {
children: [/*#__PURE__*/_jsx(MessageAlternator, {
"aria-live": "assertive",
message: assertiveMessage
}), /*#__PURE__*/_jsx(MessageAlternator, {
"aria-live": "polite",
message: politeMessage
})]
});
});
function MessageAlternator(_ref) {
var {
message = "",
"aria-live": ariaLive
} = _ref;
var messagesRef = useRef(["", ""]);
var indexRef = useRef(0);
if (message !== messagesRef.current[indexRef.current]) {
messagesRef.current[indexRef.current] = "";
indexRef.current = (indexRef.current + 1) % 2;
messagesRef.current[indexRef.current] = message;
}
return /*#__PURE__*/_jsxs(Fragment, {
children: [/*#__PURE__*/_jsx(MessageBlock, {
"aria-live": ariaLive,
message: messagesRef.current[0]
}), /*#__PURE__*/_jsx(MessageBlock, {
"aria-live": ariaLive,
message: messagesRef.current[1]
})]
});
}
function MessageBlock(_ref2) {
var {
message = "",
"aria-live": ariaLive
} = _ref2;
return /*#__PURE__*/_jsx(VisuallyHidden, {
"aria-live": ariaLive,
"aria-relevant": "additions",
"aria-atomic": "true",
children: message
});
}
//# sourceMappingURL=LiveAnnouncer.js.map