Merge pull request #3587 from matrix-org/t3chguy/a11y_message_actions_bar

Improve A11Y of timeline. Show timestamp & Actions on focus-within
This commit is contained in:
Michael Telatynski 2019-11-04 10:33:16 +00:00 committed by GitHub
commit 92ee50fb77
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 20 additions and 6 deletions

View file

@ -138,11 +138,13 @@ limitations under the License.
// Explicit relationships so that it doesn't apply to nested EventTile components (e.g in Replies) // 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_last > div > a > .mx_MessageTimestamp,
.mx_EventTile:hover > 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 { .mx_EventTile.mx_EventTile_actionBarFocused > div > a > .mx_MessageTimestamp {
visibility: visible; visibility: visible;
} }
.mx_EventTile:hover .mx_MessageActionBar, .mx_EventTile:hover .mx_MessageActionBar,
.mx_EventTile:focus-within .mx_MessageActionBar,
.mx_EventTile.mx_EventTile_actionBarFocused .mx_MessageActionBar { .mx_EventTile.mx_EventTile_actionBarFocused .mx_MessageActionBar {
visibility: visible; visibility: visible;
} }
@ -166,6 +168,7 @@ limitations under the License.
} }
.mx_EventTile:hover .mx_EventTile_line, .mx_EventTile:hover .mx_EventTile_line,
.mx_EventTile:focus-within .mx_EventTile_line,
.mx_EventTile.mx_EventTile_actionBarFocused .mx_EventTile_line { .mx_EventTile.mx_EventTile_actionBarFocused .mx_EventTile_line {
background-color: $event-selected-color; 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 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); 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 { .mx_EventTile_body .mx_EventTile_pre_container:hover .mx_EventTile_copyButton {
visibility: visible; visibility: visible;
} }

View file

@ -57,7 +57,8 @@ export default class DateSeparator extends React.Component {
render() { render() {
// ARIA treats <hr/>s as separators, here we abuse them slightly so manually treat this entire thing as one // 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"> // tab-index=-1 to allow it to be focusable but do not add tab stop for it, primarily for screen readers
return <h2 className="mx_DateSeparator" role="separator" tabIndex={-1}>
<hr role="none" /> <hr role="none" />
<div>{ this.getLabel() }</div> <div>{ this.getLabel() }</div>
<hr role="none" /> <hr role="none" />

View file

@ -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} {reactButton}
{replyButton} {replyButton}
{editButton} {editButton}

View file

@ -28,7 +28,7 @@ export default class MessageTimestamp extends React.Component {
render() { render() {
const date = new Date(this.props.ts); const date = new Date(this.props.ts);
return ( 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) } { formatTime(date, this.props.showTwelveHour) }
</span> </span>
); );

View file

@ -32,6 +32,7 @@ const TextForEvent = require('../../../TextForEvent');
import dis from '../../../dispatcher'; import dis from '../../../dispatcher';
import SettingsStore from "../../../settings/SettingsStore"; import SettingsStore from "../../../settings/SettingsStore";
import {EventStatus, MatrixClient} from 'matrix-js-sdk'; import {EventStatus, MatrixClient} from 'matrix-js-sdk';
import {formatTime} from "../../../DateUtils";
const ObjectUtils = require('../../../ObjectUtils'); const ObjectUtils = require('../../../ObjectUtils');
@ -786,14 +787,19 @@ module.exports = createReactClass({
this.props.permalinkCreator, this.props.permalinkCreator,
'replyThread', 'replyThread',
); );
// tab-index=-1 to allow it to be focusable but do not add tab stop for it, primarily for screen readers
return ( return (
<div className={classes}> <div className={classes} tabIndex={-1}>
<div className="mx_EventTile_msgOption"> <div className="mx_EventTile_msgOption">
{ readAvatars } { readAvatars }
</div> </div>
{ sender } { sender }
<div className="mx_EventTile_line"> <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 } { timestamp }
</a> </a>
{ this._renderE2EPadlock() } { this._renderE2EPadlock() }

View file

@ -1055,6 +1055,7 @@
"React": "React", "React": "React",
"Reply": "Reply", "Reply": "Reply",
"Edit": "Edit", "Edit": "Edit",
"Message Actions": "Message Actions",
"Options": "Options", "Options": "Options",
"Attachment": "Attachment", "Attachment": "Attachment",
"Error decrypting attachment": "Error decrypting attachment", "Error decrypting attachment": "Error decrypting attachment",