mirror of https://github.com/vector-im/riot-web
Improve keyboard accessibility using :focus-visible CSS polyfill
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>pull/21833/head
parent
3674b87415
commit
8d1d3090f3
|
@ -75,6 +75,7 @@
|
||||||
"filesize": "3.5.6",
|
"filesize": "3.5.6",
|
||||||
"flux": "2.1.1",
|
"flux": "2.1.1",
|
||||||
"focus-trap-react": "^3.0.5",
|
"focus-trap-react": "^3.0.5",
|
||||||
|
"focus-visible": "^5.0.2",
|
||||||
"fuse.js": "^2.2.0",
|
"fuse.js": "^2.2.0",
|
||||||
"gemini-scrollbar": "github:matrix-org/gemini-scrollbar#91e1e566",
|
"gemini-scrollbar": "github:matrix-org/gemini-scrollbar#91e1e566",
|
||||||
"gfm.css": "^1.1.1",
|
"gfm.css": "^1.1.1",
|
||||||
|
|
|
@ -18,7 +18,7 @@ limitations under the License.
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_AccessibleButton:focus {
|
.mx_AccessibleButton:focus:not(.focus-visible) {
|
||||||
outline: 0;
|
outline: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,9 @@ import * as Rooms from '../../Rooms';
|
||||||
import linkifyMatrix from "../../linkify-matrix";
|
import linkifyMatrix from "../../linkify-matrix";
|
||||||
import * as Lifecycle from '../../Lifecycle';
|
import * as Lifecycle from '../../Lifecycle';
|
||||||
// LifecycleStore is not used but does listen to and dispatch actions
|
// LifecycleStore is not used but does listen to and dispatch actions
|
||||||
require('../../stores/LifecycleStore');
|
import '../../stores/LifecycleStore';
|
||||||
|
// focus-visible is a Polyfill for the :focus-visible CSS pseudo-attribute used by _AccessibleButton.scss
|
||||||
|
import 'focus-visible';
|
||||||
import PageTypes from '../../PageTypes';
|
import PageTypes from '../../PageTypes';
|
||||||
import { getHomePageUrl } from '../../utils/pages';
|
import { getHomePageUrl } from '../../utils/pages';
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ import Modal from "../../../Modal";
|
||||||
import SdkConfig from '../../../SdkConfig';
|
import SdkConfig from '../../../SdkConfig';
|
||||||
import { getHostingLink } from '../../../utils/HostingLink';
|
import { getHostingLink } from '../../../utils/HostingLink';
|
||||||
import MatrixClientPeg from '../../../MatrixClientPeg';
|
import MatrixClientPeg from '../../../MatrixClientPeg';
|
||||||
|
import sdk from "../../../index";
|
||||||
|
|
||||||
export class TopLeftMenu extends React.Component {
|
export class TopLeftMenu extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -57,6 +58,8 @@ export class TopLeftMenu extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
||||||
|
|
||||||
const isGuest = MatrixClientPeg.get().isGuest();
|
const isGuest = MatrixClientPeg.get().isGuest();
|
||||||
|
|
||||||
const hostingSignupLink = getHostingLink('user-context-menu');
|
const hostingSignupLink = getHostingLink('user-context-menu');
|
||||||
|
@ -77,25 +80,33 @@ export class TopLeftMenu extends React.Component {
|
||||||
|
|
||||||
let homePageItem = null;
|
let homePageItem = null;
|
||||||
if (this.hasHomePage()) {
|
if (this.hasHomePage()) {
|
||||||
homePageItem = <li className="mx_TopLeftMenu_icon_home" onClick={this.viewHomePage} tabIndex={0}>
|
homePageItem = (
|
||||||
{_t("Home")}
|
<AccessibleButton element="li" className="mx_TopLeftMenu_icon_home" onClick={this.viewHomePage}>
|
||||||
</li>;
|
{_t("Home")}
|
||||||
|
</AccessibleButton>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let signInOutItem;
|
let signInOutItem;
|
||||||
if (isGuest) {
|
if (isGuest) {
|
||||||
signInOutItem = <li className="mx_TopLeftMenu_icon_signin" onClick={this.signIn} tabIndex={0}>
|
signInOutItem = (
|
||||||
{_t("Sign in")}
|
<AccessibleButton element="li" className="mx_TopLeftMenu_icon_signin" onClick={this.signIn}>
|
||||||
</li>;
|
{_t("Sign in")}
|
||||||
|
</AccessibleButton>
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
signInOutItem = <li className="mx_TopLeftMenu_icon_signout" onClick={this.signOut} tabIndex={0}>
|
signInOutItem = (
|
||||||
{_t("Sign out")}
|
<AccessibleButton element="li" className="mx_TopLeftMenu_icon_signout" onClick={this.signOut}>
|
||||||
</li>;
|
{_t("Sign out")}
|
||||||
|
</AccessibleButton>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const settingsItem = <li className="mx_TopLeftMenu_icon_settings" onClick={this.openSettings} tabIndex={0}>
|
const settingsItem = (
|
||||||
{_t("Settings")}
|
<AccessibleButton element="li" className="mx_TopLeftMenu_icon_settings" onClick={this.openSettings}>
|
||||||
</li>;
|
{_t("Settings")}
|
||||||
|
</AccessibleButton>
|
||||||
|
);
|
||||||
|
|
||||||
return <div className="mx_TopLeftMenu mx_HiddenFocusable" tabIndex={0} ref={this.props.containerRef}>
|
return <div className="mx_TopLeftMenu mx_HiddenFocusable" tabIndex={0} ref={this.props.containerRef}>
|
||||||
<div className="mx_TopLeftMenu_section_noIcon" aria-readonly={true}>
|
<div className="mx_TopLeftMenu_section_noIcon" aria-readonly={true}>
|
||||||
|
|
|
@ -140,6 +140,8 @@ export default class MessageActionBar extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
||||||
|
|
||||||
let reactButton;
|
let reactButton;
|
||||||
let replyButton;
|
let replyButton;
|
||||||
let editButton;
|
let editButton;
|
||||||
|
@ -149,14 +151,16 @@ export default class MessageActionBar extends React.PureComponent {
|
||||||
reactButton = this.renderReactButton();
|
reactButton = this.renderReactButton();
|
||||||
}
|
}
|
||||||
if (this.context.room.canReply) {
|
if (this.context.room.canReply) {
|
||||||
replyButton = <span className="mx_MessageActionBar_maskButton mx_MessageActionBar_replyButton"
|
replyButton = <AccessibleButton
|
||||||
|
className="mx_MessageActionBar_maskButton mx_MessageActionBar_replyButton"
|
||||||
title={_t("Reply")}
|
title={_t("Reply")}
|
||||||
onClick={this.onReplyClick}
|
onClick={this.onReplyClick}
|
||||||
/>;
|
/>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (canEditContent(this.props.mxEvent)) {
|
if (canEditContent(this.props.mxEvent)) {
|
||||||
editButton = <span className="mx_MessageActionBar_maskButton mx_MessageActionBar_editButton"
|
editButton = <AccessibleButton
|
||||||
|
className="mx_MessageActionBar_maskButton mx_MessageActionBar_editButton"
|
||||||
title={_t("Edit")}
|
title={_t("Edit")}
|
||||||
onClick={this.onEditClick}
|
onClick={this.onEditClick}
|
||||||
/>;
|
/>;
|
||||||
|
@ -166,7 +170,7 @@ export default class MessageActionBar extends React.PureComponent {
|
||||||
{reactButton}
|
{reactButton}
|
||||||
{replyButton}
|
{replyButton}
|
||||||
{editButton}
|
{editButton}
|
||||||
<span
|
<AccessibleButton
|
||||||
className="mx_MessageActionBar_maskButton mx_MessageActionBar_optionsButton"
|
className="mx_MessageActionBar_maskButton mx_MessageActionBar_optionsButton"
|
||||||
title={_t("Options")}
|
title={_t("Options")}
|
||||||
onClick={this.onOptionsClick}
|
onClick={this.onOptionsClick}
|
||||||
|
|
|
@ -3367,6 +3367,11 @@ focus-trap@^2.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
tabbable "^1.0.3"
|
tabbable "^1.0.3"
|
||||||
|
|
||||||
|
focus-visible@^5.0.2:
|
||||||
|
version "5.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/focus-visible/-/focus-visible-5.0.2.tgz#4fae9cf40458b73c10701c9774c462e3ccd53caf"
|
||||||
|
integrity sha512-zT2fj/bmOgEBjqGbURGlowTmCwsIs3bRDMr/sFZz8Ly7VkEiwuCn9swNTL3pPuf8Oua2de7CLuKdnuNajWdDsQ==
|
||||||
|
|
||||||
follow-redirects@^1.0.0:
|
follow-redirects@^1.0.0:
|
||||||
version "1.7.0"
|
version "1.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.7.0.tgz#489ebc198dc0e7f64167bd23b03c4c19b5784c76"
|
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.7.0.tgz#489ebc198dc0e7f64167bd23b03c4c19b5784c76"
|
||||||
|
|
Loading…
Reference in New Issue