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
This commit is contained in:
Emmanuel Pelletier 2023-02-28 15:52:06 +01:00 committed by GitHub
parent fed74afffe
commit 72dd609247
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 73 additions and 8 deletions

View File

@ -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"
}
}
}

View File

@ -46,9 +46,12 @@ function Header({ onCancel, className, isPollsEnabled, t }: Props) {
return (
<div
className = { className || 'chat-dialog-header' }
role = 'heading'>
{ t(isPollsEnabled ? 'chat.titleWithPolls' : 'chat.title') }
className = { className || 'chat-dialog-header' }>
<span
aria-level = { 1 }
role = 'heading'>
{ t(isPollsEnabled ? 'chat.titleWithPolls' : 'chat.title') }
</span>
<Icon
ariaLabel = { t('toolbar.closeChat') }
onClick = { onCancel }

View File

@ -210,7 +210,8 @@ class Conference extends AbstractConference<Props, *> {
_notificationsVisible,
_overflowDrawer,
_showLobby,
_showPrejoin
_showPrejoin,
t
} = this.props;
return (
@ -240,7 +241,17 @@ class Conference extends AbstractConference<Props, *> {
}
</div>
{ _showPrejoin || _showLobby || <Toolbox /> }
{ _showPrejoin || _showLobby || (
<>
<span
aria-level = { 1 }
className = 'sr-only'
role = 'heading'>
{ t('toolbar.accessibilityLabel.heading') }
</span>
<Toolbox />
</>
)}
{_notificationsVisible && !_isAnyOverlayVisible && (_overflowDrawer
? <JitsiPortal className = 'notification-portal'>

View File

@ -343,7 +343,8 @@ class Filmstrip extends PureComponent <IProps, IState> {
_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 <IProps, IState> {
_verticalViewGrid && 'no-vertical-padding',
_verticalViewBackground && classes.filmstripBackground) }
style = { filmstripStyle }>
<span
aria-level = { 1 }
className = 'sr-only'
role = 'heading'>
{ t('filmstrip.accessibilityLabel.heading') }
</span>
{ toolbar }
{_resizableFilmstrip
? <div

View File

@ -112,6 +112,12 @@ function MeetingParticipants({
return (
<>
<span
aria-level = { 1 }
className = 'sr-only'
role = 'heading'>
{ t('participantsPane.title') }
</span>
<div className = { cx(styles.heading, styles.headingW) }>
{visitorsCount && visitorsCount > 0
&& t('participantsPane.headings.visitors', { count: visitorsCount })}

View File

@ -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<any>(null);
const collabAPIRef = useRef<any>(null);
@ -113,6 +126,20 @@ const Whiteboard: () => JSX.Element = () => {
{
isOpen && (
<div className = 'excalidraw-wrapper'>
{/*
* 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.
*/
<span
aria-level = { 1 }
className = 'sr-only'
role = 'heading'>
{ props.t('whiteboard.accessibilityLabel.heading') }
</span>
}
<ExcalidrawApp
collabDetails = { collabDetails }
collabServerUrl = { collabServerUrl }
@ -132,4 +159,4 @@ const Whiteboard: () => JSX.Element = () => {
);
};
export default Whiteboard;
export default translate(Whiteboard);