From 72dd609247c1301a96a66f648a2779577c247019 Mon Sep 17 00:00:00 2001 From: Emmanuel Pelletier Date: Tue, 28 Feb 2023 15:52:06 +0100 Subject: [PATCH] feat(a11y) add headings across the app for easier screen reader nav (#12427) feat(a11y): added headings across the app for easier screen reader nav --- lang/main.json | 11 +++++++ .../chat/components/web/ChatHeader.js | 9 ++++-- .../conference/components/web/Conference.js | 15 +++++++-- .../filmstrip/components/web/Filmstrip.tsx | 9 +++++- .../components/web/MeetingParticipants.tsx | 6 ++++ .../whiteboard/components/web/Whiteboard.tsx | 31 +++++++++++++++++-- 6 files changed, 73 insertions(+), 8 deletions(-) diff --git a/lang/main.json b/lang/main.json index 5a4ede91c..71d39f231 100644 --- a/lang/main.json +++ b/lang/main.json @@ -452,6 +452,11 @@ "veryBad": "Very Bad", "veryGood": "Very Good" }, + "filmstrip": { + "accessibilityLabel": { + "heading": "Video thumbnails" + } + }, "giphy": { "noResults": "No results found :(", "search": "Search GIPHY" @@ -1097,6 +1102,7 @@ "giphy": "Toggle GIPHY menu", "grantModerator": "Grant Moderator Rights", "hangup": "Leave the meeting", + "heading": "Toolbar", "help": "Help", "invite": "Invite people", "kick": "Kick participant", @@ -1393,5 +1399,10 @@ "terms": "Terms", "title": "Secure, fully featured, and completely free video conferencing", "upcomingMeetings": "Your upcoming meetings" + }, + "whiteboard": { + "accessibilityLabel": { + "heading": "Whiteboard" + } } } diff --git a/react/features/chat/components/web/ChatHeader.js b/react/features/chat/components/web/ChatHeader.js index 184151c83..0b5b476a0 100644 --- a/react/features/chat/components/web/ChatHeader.js +++ b/react/features/chat/components/web/ChatHeader.js @@ -46,9 +46,12 @@ function Header({ onCancel, className, isPollsEnabled, t }: Props) { return (
- { t(isPollsEnabled ? 'chat.titleWithPolls' : 'chat.title') } + className = { className || 'chat-dialog-header' }> + + { t(isPollsEnabled ? 'chat.titleWithPolls' : 'chat.title') } + { _notificationsVisible, _overflowDrawer, _showLobby, - _showPrejoin + _showPrejoin, + t } = this.props; return ( @@ -240,7 +241,17 @@ class Conference extends AbstractConference { }
- { _showPrejoin || _showLobby || } + { _showPrejoin || _showLobby || ( + <> + + { t('toolbar.accessibilityLabel.heading') } + + + + )} {_notificationsVisible && !_isAnyOverlayVisible && (_overflowDrawer ? diff --git a/react/features/filmstrip/components/web/Filmstrip.tsx b/react/features/filmstrip/components/web/Filmstrip.tsx index b9214e1de..4a6034141 100644 --- a/react/features/filmstrip/components/web/Filmstrip.tsx +++ b/react/features/filmstrip/components/web/Filmstrip.tsx @@ -343,7 +343,8 @@ class Filmstrip extends PureComponent { _verticalViewGrid, _verticalViewMaxWidth, classes, - filmstripType + filmstripType, + t } = this.props; const { isMouseDown } = this.state; const tileViewActive = _currentLayout === LAYOUTS.TILE_VIEW; @@ -434,6 +435,12 @@ class Filmstrip extends PureComponent { _verticalViewGrid && 'no-vertical-padding', _verticalViewBackground && classes.filmstripBackground) } style = { filmstripStyle }> + + { t('filmstrip.accessibilityLabel.heading') } + { toolbar } {_resizableFilmstrip ?
+ + { t('participantsPane.title') } +
{visitorsCount && visitorsCount > 0 && t('participantsPane.headings.visitors', { count: visitorsCount })} diff --git a/react/features/whiteboard/components/web/Whiteboard.tsx b/react/features/whiteboard/components/web/Whiteboard.tsx index d42b1f2dc..999050785 100644 --- a/react/features/whiteboard/components/web/Whiteboard.tsx +++ b/react/features/whiteboard/components/web/Whiteboard.tsx @@ -6,6 +6,7 @@ import { useSelector } from 'react-redux'; // @ts-expect-error import Filmstrip from '../../../../../modules/UI/videolayout/Filmstrip'; import { IReduxState } from '../../../app/types'; +import { translate } from '../../../base/i18n/functions'; import { getLocalParticipant } from '../../../base/participants/functions'; import { getVerticalViewMaxWidth } from '../../../filmstrip/functions.web'; import { getToolboxHeight } from '../../../toolbox/functions.web'; @@ -32,12 +33,24 @@ interface IDimensions { width: string; } +/** + * The type of the React {@link Component} props of {@link Whiteboard}. + */ +type Props = { + + /** + * Invoked to obtain translated strings. + */ + t: Function; +}; + /** * The Whiteboard component. * + * @param {Props} props - The React props passed to this component. * @returns {JSX.Element} - The React component. */ -const Whiteboard: () => JSX.Element = () => { +const Whiteboard = (props: Props): JSX.Element => { const excalidrawRef = useRef(null); const collabAPIRef = useRef(null); @@ -113,6 +126,20 @@ const Whiteboard: () => JSX.Element = () => { { isOpen && (
+ {/* + * Excalidraw renders a few lvl 2 headings. This is + * quite fortunate, because we actually use lvl 1 + * headings to mark the big sections of our app. So make + * sure to mark the Excalidraw context with a lvl 1 + * heading before showing the whiteboard. + */ + + { props.t('whiteboard.accessibilityLabel.heading') } + + } JSX.Element = () => { ); }; -export default Whiteboard; +export default translate(Whiteboard);