UNPKG

@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
/* * 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