From fd4cdd0dec78d2ea3085ab8b752a394c3f08bea9 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 1 Nov 2019 10:50:58 +0000 Subject: [PATCH] Improve A11Y of timeline. Show TS & Actions on focus-within --- res/css/views/rooms/_EventTile.scss | 7 ++++++- src/components/views/messages/DateSeparator.js | 2 +- src/components/views/messages/MessageActionBar.js | 3 ++- src/components/views/messages/MessageTimestamp.js | 2 +- src/components/views/rooms/EventTile.js | 9 +++++++-- src/i18n/strings/en_EN.json | 1 + 6 files changed, 18 insertions(+), 6 deletions(-) diff --git a/res/css/views/rooms/_EventTile.scss b/res/css/views/rooms/_EventTile.scss index fafd34f8ca..a30b219016 100644 --- a/res/css/views/rooms/_EventTile.scss +++ b/res/css/views/rooms/_EventTile.scss @@ -138,11 +138,13 @@ limitations under the License. // Explicit relationships so that it doesn't apply to nested EventTile components (e.g in Replies) .mx_EventTile_last > div > a > .mx_MessageTimestamp, .mx_EventTile:hover > div > a > .mx_MessageTimestamp, +.mx_EventTile:focus-within > div > a > .mx_MessageTimestamp, .mx_EventTile.mx_EventTile_actionBarFocused > div > a > .mx_MessageTimestamp { visibility: visible; } .mx_EventTile:hover .mx_MessageActionBar, +.mx_EventTile:focus-within .mx_MessageActionBar, .mx_EventTile.mx_EventTile_actionBarFocused .mx_MessageActionBar { visibility: visible; } @@ -166,6 +168,7 @@ limitations under the License. } .mx_EventTile:hover .mx_EventTile_line, +.mx_EventTile:focus-within .mx_EventTile_line, .mx_EventTile.mx_EventTile_actionBarFocused .mx_EventTile_line { background-color: $event-selected-color; } @@ -465,7 +468,8 @@ div.mx_EventTile_notSent.mx_EventTile_redacted .mx_UnknownBody { } } -.mx_EventTile:hover .mx_EventTile_body pre { +.mx_EventTile:hover .mx_EventTile_body pre, +.mx_EventTile:focus-within .mx_EventTile_body pre { border: 1px solid #e5e5e5; // deliberate constant as we're behind an invert filter } @@ -487,6 +491,7 @@ div.mx_EventTile_notSent.mx_EventTile_redacted .mx_UnknownBody { background-image: url($copy-button-url); } +.mx_EventTile_body .mx_EventTile_pre_container:focus-within .mx_EventTile_copyButton, .mx_EventTile_body .mx_EventTile_pre_container:hover .mx_EventTile_copyButton { visibility: visible; } diff --git a/src/components/views/messages/DateSeparator.js b/src/components/views/messages/DateSeparator.js index 900fd61914..88b59d0c26 100644 --- a/src/components/views/messages/DateSeparator.js +++ b/src/components/views/messages/DateSeparator.js @@ -57,7 +57,7 @@ export default class DateSeparator extends React.Component { render() { // ARIA treats <hr/>s as separators, here we abuse them slightly so manually treat this entire thing as one - return <h2 className="mx_DateSeparator" role="separator"> + return <h2 className="mx_DateSeparator" role="separator" tabIndex={-1}> <hr role="none" /> <div>{ this.getLabel() }</div> <hr role="none" /> diff --git a/src/components/views/messages/MessageActionBar.js b/src/components/views/messages/MessageActionBar.js index 565c66410e..acd8263410 100644 --- a/src/components/views/messages/MessageActionBar.js +++ b/src/components/views/messages/MessageActionBar.js @@ -180,7 +180,8 @@ export default class MessageActionBar extends React.PureComponent { />; } - return <div className="mx_MessageActionBar"> + // aria-live=off to not have this read out automatically as navigating around timeline, gets repetitive. + return <div className="mx_MessageActionBar" role="toolbar" aria-label={_t("Message Actions")} aria-live="off"> {reactButton} {replyButton} {editButton} diff --git a/src/components/views/messages/MessageTimestamp.js b/src/components/views/messages/MessageTimestamp.js index 0bbb3f631e..199a6f47ce 100644 --- a/src/components/views/messages/MessageTimestamp.js +++ b/src/components/views/messages/MessageTimestamp.js @@ -28,7 +28,7 @@ export default class MessageTimestamp extends React.Component { render() { const date = new Date(this.props.ts); return ( - <span className="mx_MessageTimestamp" title={formatFullDate(date, this.props.showTwelveHour)}> + <span className="mx_MessageTimestamp" title={formatFullDate(date, this.props.showTwelveHour)} aria-hidden={true}> { formatTime(date, this.props.showTwelveHour) } </span> ); diff --git a/src/components/views/rooms/EventTile.js b/src/components/views/rooms/EventTile.js index ca83dd1814..bc502d0674 100644 --- a/src/components/views/rooms/EventTile.js +++ b/src/components/views/rooms/EventTile.js @@ -32,6 +32,7 @@ const TextForEvent = require('../../../TextForEvent'); import dis from '../../../dispatcher'; import SettingsStore from "../../../settings/SettingsStore"; import {EventStatus, MatrixClient} from 'matrix-js-sdk'; +import {formatTime} from "../../../DateUtils"; const ObjectUtils = require('../../../ObjectUtils'); @@ -787,13 +788,17 @@ module.exports = createReactClass({ 'replyThread', ); return ( - <div className={classes}> + <div className={classes} tabIndex={-1}> <div className="mx_EventTile_msgOption"> { readAvatars } </div> { sender } <div className="mx_EventTile_line"> - <a href={permalink} onClick={this.onPermalinkClicked}> + <a + href={permalink} + onClick={this.onPermalinkClicked} + aria-label={formatTime(new Date(this.props.mxEvent.getTs()), this.props.isTwelveHour)} + > { timestamp } </a> { this._renderE2EPadlock() } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 524a8a1abf..86521f2594 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1053,6 +1053,7 @@ "React": "React", "Reply": "Reply", "Edit": "Edit", + "Message Actions": "Message Actions", "Options": "Options", "Attachment": "Attachment", "Error decrypting attachment": "Error decrypting attachment",