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:
commit
92ee50fb77
6 changed files with 20 additions and 6 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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" />
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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() }
|
||||||
|
|
|
@ -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",
|
||||||
|
|
Loading…
Reference in a new issue