📣 a11y: Better Screen Reader Announcements (#3693)

* refactor: Improve LiveAnnouncer component

The LiveAnnouncer component in the client/src/a11y/LiveAnnouncer.tsx file has been refactored to improve its functionality. The component now processes text in chunks for better performance and adds a minimum announcement delay to prevent overlapping announcements. Additionally, the component now properly clears the announcement message and ID before setting a new one. These changes enhance the accessibility and user experience of the LiveAnnouncer component.

* refactor: manage only 2 LiveAnnouncer aria-live elements, queue assertive/polite together

* refactor: use localizations for event announcements

* refactor: update minimum announcement delay in LiveAnnouncer component

* refactor: replace *`_

* chore(useContentHandler): typing

* chore: more type fixes and safely announce final message
This commit is contained in:
Danny Avila 2024-08-19 03:51:17 -04:00 committed by GitHub
parent 598e2be225
commit cebb3751c1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 152 additions and 105 deletions

View file

@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react';
import React from 'react';
import MessageBlock from './MessageBlock';
interface AnnouncerProps {
@ -8,45 +8,11 @@ interface AnnouncerProps {
assertiveMessageId: string;
}
const Announcer: React.FC<AnnouncerProps> = ({
politeMessage,
politeMessageId,
assertiveMessage,
assertiveMessageId,
}) => {
const [state, setState] = useState({
assertiveMessage1: '',
assertiveMessage2: '',
politeMessage1: '',
politeMessage2: '',
setAlternatePolite: false,
setAlternateAssertive: false,
});
useEffect(() => {
setState((prevState) => ({
...prevState,
politeMessage1: prevState.setAlternatePolite ? '' : politeMessage,
politeMessage2: prevState.setAlternatePolite ? politeMessage : '',
setAlternatePolite: !prevState.setAlternatePolite,
}));
}, [politeMessage, politeMessageId]);
useEffect(() => {
setState((prevState) => ({
...prevState,
assertiveMessage1: prevState.setAlternateAssertive ? '' : assertiveMessage,
assertiveMessage2: prevState.setAlternateAssertive ? assertiveMessage : '',
setAlternateAssertive: !prevState.setAlternateAssertive,
}));
}, [assertiveMessage, assertiveMessageId]);
const Announcer: React.FC<AnnouncerProps> = ({ politeMessage, assertiveMessage }) => {
return (
<div>
<MessageBlock aria-live="assertive" aria-atomic="true" message={state.assertiveMessage1} />
<MessageBlock aria-live="assertive" aria-atomic="true" message={state.assertiveMessage2} />
<MessageBlock aria-live="polite" aria-atomic="false" message={state.politeMessage1} />
<MessageBlock aria-live="polite" aria-atomic="false" message={state.politeMessage2} />
<MessageBlock aria-live="assertive" aria-atomic="true" message={assertiveMessage} />
<MessageBlock aria-live="polite" aria-atomic="false" message={politeMessage} />
</div>
);
};