From 6c5b777a778616a9f22d3e1df809d11bf9914d40 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Thu, 28 Nov 2019 18:16:59 +0000
Subject: [PATCH] Consolidate all except tooltips
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
---
src/components/structures/ContextualMenu.js | 136 +++++++++++++-----
.../structures/TopLeftMenuButton.js | 33 ++---
.../avatars/MemberStatusMessageAvatar.js | 40 +++---
.../views/context_menus/WidgetContextMenu.js | 27 ++--
src/components/views/elements/AppTile.js | 90 ++++++------
src/components/views/elements/TagTile.js | 16 ++-
.../views/groups/GroupInviteTile.js | 15 +-
.../views/messages/MessageActionBar.js | 59 ++------
src/components/views/rooms/RoomTile.js | 11 +-
9 files changed, 231 insertions(+), 196 deletions(-)
diff --git a/src/components/structures/ContextualMenu.js b/src/components/structures/ContextualMenu.js
index dcf670f01d..d332f8f824 100644
--- a/src/components/structures/ContextualMenu.js
+++ b/src/components/structures/ContextualMenu.js
@@ -16,13 +16,14 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import React from 'react';
+import React, {useRef, useState} from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import {focusCapturedRef} from "../../utils/Accessibility";
import {Key, KeyCode} from "../../Keyboard";
import sdk from "../../index";
+import AccessibleButton from "../views/elements/AccessibleButton";
// Shamelessly ripped off Modal.js. There's probably a better way
// of doing reusable widgets like dialog boxes & menus where we go and
@@ -222,7 +223,7 @@ export default class ContextualMenu extends React.Component {
return
{ chevron }
-
+
{ props.hasBackground &&
}
@@ -231,8 +232,10 @@ export default class ContextualMenu extends React.Component {
}
const ARIA_MENU_ITEM_ROLES = new Set(["menuitem", "menuitemcheckbox", "menuitemradio"]);
-
-class ContextualMenu2 extends React.Component {
+// Generic ContextMenu Portal wrapper
+// all options inside the menu should be of role=menuitem/menuitemcheckbox/menuitemradiobutton and have tabIndex={-1}
+// this will allow the ContextMenu to manage its own focus using arrow keys as per the ARIA guidelines.
+export class ContextMenu extends React.Component {
propTypes: {
top: PropTypes.number,
bottom: PropTypes.number,
@@ -243,7 +246,7 @@ class ContextualMenu2 extends React.Component {
chevronOffset: PropTypes.number,
chevronFace: PropTypes.string, // top, bottom, left, right or none
// Function to be called on menu close
- onFinished: PropTypes.func,
+ onFinished: PropTypes.func.isRequired,
menuPaddingTop: PropTypes.number,
menuPaddingRight: PropTypes.number,
menuPaddingBottom: PropTypes.number,
@@ -258,10 +261,14 @@ class ContextualMenu2 extends React.Component {
windowResize: PropTypes.func,
};
+ static defaultProps = {
+ hasBackground: true,
+ };
+
constructor() {
super();
this.state = {
- contextMenuRect: null,
+ contextMenuElem: null,
};
// persist what had focus when we got initialized so we can return it after
@@ -277,19 +284,22 @@ class ContextualMenu2 extends React.Component {
// We don't need to clean up when unmounting, so ignore
if (!element) return;
- const first = element.querySelector('[role^="menuitem"]');
+ let first = element.querySelector('[role^="menuitem"]');
+ if (!first) {
+ first = element.querySelector('[tab-index]');
+ }
if (first) {
first.focus();
}
this.setState({
- contextMenuRect: element.getBoundingClientRect(),
+ contextMenuElem: element,
});
};
onContextMenu = (e) => {
- if (this.props.closeMenu) {
- this.props.closeMenu();
+ if (this.props.onFinished) {
+ this.props.onFinished();
e.preventDefault();
const x = e.clientX;
@@ -347,13 +357,25 @@ class ContextualMenu2 extends React.Component {
}
};
- _onKeyDown = (ev) => {
- let handled = true;
+ _onMoveFocusHomeEnd = (element, up) => {
+ let results = element.querySelectorAll('[role^="menuitem"]');
+ if (!results) {
+ results = element.querySelectorAll('[tab-index]');
+ }
+ if (results && results.length) {
+ if (up) {
+ results[0].focus();
+ } else {
+ results[results.length - 1].focus();
+ }
+ }
+ };
+ _onKeyDown = (ev) => {
switch (ev.key) {
case Key.TAB:
case Key.ESCAPE:
- this.props.closeMenu();
+ this.props.onFinished();
break;
case Key.ARROW_UP:
this._onMoveFocus(ev.target, true);
@@ -361,14 +383,17 @@ class ContextualMenu2 extends React.Component {
case Key.ARROW_DOWN:
this._onMoveFocus(ev.target, false);
break;
- default:
- handled = false;
+ case Key.HOME:
+ this._onMoveFocusHomeEnd(this.state.contextMenuElem, true);
+ break;
+ case Key.END:
+ this._onMoveFocusHomeEnd(this.state.contextMenuElem, false);
+ break;
}
- if (handled) {
- ev.stopPropagation();
- ev.preventDefault();
- }
+ // consume all other keys in context menu
+ ev.stopPropagation();
+ ev.preventDefault();
};
render() {
@@ -390,7 +415,7 @@ class ContextualMenu2 extends React.Component {
chevronFace = 'right';
}
- const contextMenuRect = this.state.contextMenuRect || null;
+ const contextMenuRect = this.state.contextMenuElem ? this.state.contextMenuElem.getBoundingClientRect() : null;
const padding = 10;
const chevronOffset = {};
@@ -465,37 +490,36 @@ class ContextualMenu2 extends React.Component {
let background;
if (props.hasBackground) {
background = (
-
+
);
}
- return (
+ const menu = (
-
+
{ chevron }
{ props.children }
{ background }
);
+ return ReactDOM.createPortal(menu, getOrCreateContainer());
}
}
-// Generic ContextMenu Portal wrapper
-// all options inside the menu should be of role=menuitem/menuitemcheckbox/menuitemradiobutton and have tabIndex={-1}
-// this will allow the ContextMenu to manage its own focus using arrow keys as per the ARIA guidelines.
-
-export const ContextMenu = ({children, onFinished, props, hasBackground=true}) => {
- const menu =
- { children }
- ;
-
- return ReactDOM.createPortal(menu, getOrCreateContainer());
+// Semantic component for representing the AccessibleButton which launches a
+export const ContextMenuButton = ({ label, isExpanded, children, ...props }) => {
+ const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
+ return (
+
+ { children }
+
+ );
+};
+ContextMenuButton.propTypes = {
+ ...AccessibleButton.propTypes,
+ label: PropTypes.string.isRequired,
+ isExpanded: PropTypes.bool.isRequired, // whether or not the context menu is currently open
};
// Semantic component for representing a role=menuitem
@@ -508,6 +532,7 @@ export const MenuItem = ({children, label, ...props}) => {
);
};
MenuItem.propTypes = {
+ ...AccessibleButton.propTypes,
label: PropTypes.string, // optional
className: PropTypes.string, // optional
onClick: PropTypes.func.isRequired,
@@ -520,6 +545,7 @@ export const MenuGroup = ({children, label, ...props}) => {
;
};
MenuGroup.propTypes = {
+ ...AccessibleButton.propTypes,
label: PropTypes.string.isRequired,
className: PropTypes.string, // optional
};
@@ -534,6 +560,7 @@ export const MenuItemCheckbox = ({children, label, active=false, disabled=false,
);
};
MenuItemCheckbox.propTypes = {
+ ...AccessibleButton.propTypes,
label: PropTypes.string, // optional
active: PropTypes.bool.isRequired,
disabled: PropTypes.bool, // optional
@@ -551,6 +578,7 @@ export const MenuItemRadio = ({children, label, active=false, disabled=false, ..
);
};
MenuItemRadio.propTypes = {
+ ...AccessibleButton.propTypes,
label: PropTypes.string, // optional
active: PropTypes.bool.isRequired,
disabled: PropTypes.bool, // optional
@@ -566,6 +594,38 @@ export const toRightOf = (elementRect, chevronOffset=12) => {
return {left, top};
};
+// Placement method for
to position context menu right-aligned and flowing to the left of elementRect
+export const aboveLeft = (elementRect, chevronFace="none") => {
+ const menuOptions = { chevronFace };
+
+ const buttonRight = elementRect.right + window.pageXOffset;
+ const buttonBottom = elementRect.bottom + window.pageYOffset;
+ const buttonTop = elementRect.top + window.pageYOffset;
+ // Align the right edge of the menu to the right edge of the button
+ menuOptions.right = window.innerWidth - buttonRight;
+ // Align the menu vertically on whichever side of the button has more space available.
+ if (buttonBottom < window.innerHeight / 2) {
+ menuOptions.top = buttonBottom;
+ } else {
+ menuOptions.bottom = window.innerHeight - buttonTop;
+ }
+
+ return menuOptions;
+};
+
+export const useContextMenu = () => {
+ const _button = useRef(null);
+ const [isOpen, setIsOpen] = useState(false);
+ const open = () => {
+ setIsOpen(true);
+ };
+ const close = () => {
+ setIsOpen(false);
+ };
+
+ return [isOpen, _button, open, close, setIsOpen];
+};
+
export function createMenu(ElementClass, props, hasBackground=true) {
const closeMenu = function(...args) {
ReactDOM.unmountComponentAtNode(getOrCreateContainer());
diff --git a/src/components/structures/TopLeftMenuButton.js b/src/components/structures/TopLeftMenuButton.js
index e0875efb42..49e3ab949c 100644
--- a/src/components/structures/TopLeftMenuButton.js
+++ b/src/components/structures/TopLeftMenuButton.js
@@ -23,7 +23,7 @@ import MatrixClientPeg from '../../MatrixClientPeg';
import Avatar from '../../Avatar';
import { _t } from '../../languageHandler';
import dis from "../../dispatcher";
-import {ContextMenu} from "./ContextualMenu";
+import {ContextMenu, ContextMenuButton} from "./ContextualMenu";
import sdk from "../../index";
const AVATAR_SIZE = 28;
@@ -119,29 +119,26 @@ export default class TopLeftMenuButton extends React.Component {
let contextMenu;
if (this.state.menuDisplayed) {
const elementRect = this._buttonRef.getBoundingClientRect();
- const x = elementRect.left;
- const y = elementRect.top + elementRect.height;
- const props = {
- chevronFace: "none",
- left: x,
- top: y,
- };
-
- contextMenu =
-
- ;
+ contextMenu = (
+
+
+
+ );
}
- const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
return
- this._buttonRef = r}
- aria-label={_t("Your profile")}
- aria-haspopup={true}
- aria-expanded={this.state.menuDisplayed}
+ label={_t("Your profile")}
+ isExpanded={this.state.menuDisplayed}
>
{ nameElement }
{ chevronElement }
-
+
{ contextMenu }
;
diff --git a/src/components/views/avatars/MemberStatusMessageAvatar.js b/src/components/views/avatars/MemberStatusMessageAvatar.js
index df84964a6e..cf7ca9057e 100644
--- a/src/components/views/avatars/MemberStatusMessageAvatar.js
+++ b/src/components/views/avatars/MemberStatusMessageAvatar.js
@@ -17,12 +17,12 @@ limitations under the License.
import React, {createRef} from 'react';
import PropTypes from 'prop-types';
import MatrixClientPeg from '../../../MatrixClientPeg';
-import AccessibleButton from '../elements/AccessibleButton';
+import {_t} from "../../../languageHandler";
import MemberAvatar from '../avatars/MemberAvatar';
import classNames from 'classnames';
import StatusMessageContextMenu from "../context_menus/StatusMessageContextMenu";
import SettingsStore from "../../../settings/SettingsStore";
-import {ContextMenu} from "../../structures/ContextualMenu";
+import {ContextMenu, ContextMenuButton} from "../../structures/ContextualMenu";
export default class MemberStatusMessageAvatar extends React.Component {
static propTypes = {
@@ -118,29 +118,33 @@ export default class MemberStatusMessageAvatar extends React.Component {
if (this.state.menuDisplayed) {
const elementRect = this._button.current.getBoundingClientRect();
- const x = (elementRect.left + window.pageXOffset);
const chevronWidth = 16; // See .mx_ContextualMenu_chevron_bottom
- const chevronOffset = (elementRect.width - chevronWidth) / 2;
const chevronMargin = 1; // Add some spacing away from target
- const y = elementRect.top + window.pageYOffset - chevronMargin;
- const props = {
- chevronOffset: chevronOffset,
- chevronFace: 'bottom',
- left: x,
- top: y,
- menuWidth: 226,
- };
-
- contextMenu =
-
- ;
+ contextMenu = (
+
+
+
+ );
}
return
-
+
{avatar}
-
+
{ contextMenu }
;
diff --git a/src/components/views/context_menus/WidgetContextMenu.js b/src/components/views/context_menus/WidgetContextMenu.js
index 43e7e172cc..a8decd0f6a 100644
--- a/src/components/views/context_menus/WidgetContextMenu.js
+++ b/src/components/views/context_menus/WidgetContextMenu.js
@@ -16,8 +16,8 @@ limitations under the License.
import React from 'react';
import PropTypes from 'prop-types';
-import sdk from '../../../index';
import {_t} from '../../../languageHandler';
+import {MenuItem} from "../../structures/ContextualMenu";
export default class WidgetContextMenu extends React.Component {
static propTypes = {
@@ -71,50 +71,45 @@ export default class WidgetContextMenu extends React.Component {
};
render() {
- const AccessibleButton = sdk.getComponent("views.elements.AccessibleButton");
-
const options = [];
if (this.props.onEditClicked) {
options.push(
-
+ ,
+ ,
);
}
if (this.props.onReloadClicked) {
options.push(
-
+ ,
+ ,
);
}
if (this.props.onSnapshotClicked) {
options.push(
-
+ ,
+ ,
);
}
if (this.props.onDeleteClicked) {
options.push(
-
+ ,
+ ,
);
}
// Push this last so it appears last. It's always present.
options.push(
-
+ ,
+ ,
);
// Put separators between the options
diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js
index 9a29843d3b..b04de8a9c4 100644
--- a/src/components/views/elements/AppTile.js
+++ b/src/components/views/elements/AppTile.js
@@ -18,7 +18,7 @@ limitations under the License.
import url from 'url';
import qs from 'querystring';
-import React from 'react';
+import React, {createRef} from 'react';
import PropTypes from 'prop-types';
import MatrixClientPeg from '../../../MatrixClientPeg';
import WidgetMessaging from '../../../WidgetMessaging';
@@ -35,7 +35,7 @@ import ActiveWidgetStore from '../../../stores/ActiveWidgetStore';
import classNames from 'classnames';
import {IntegrationManagers} from "../../../integrations/IntegrationManagers";
import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore";
-import {createMenu} from "../../structures/ContextualMenu";
+import {aboveLeft, ContextMenu, ContextMenuButton} from "../../structures/ContextualMenu";
import PersistedElement from "./PersistedElement";
const ALLOWED_APP_URL_SCHEMES = ['https:', 'http:'];
@@ -62,6 +62,8 @@ export default class AppTile extends React.Component {
this._revokeWidgetPermission = this._revokeWidgetPermission.bind(this);
this._onPopoutWidgetClick = this._onPopoutWidgetClick.bind(this);
this._onReloadWidgetClick = this._onReloadWidgetClick.bind(this);
+
+ this._contextMenuButton = createRef();
}
/**
@@ -89,6 +91,7 @@ export default class AppTile extends React.Component {
error: null,
deleting: false,
widgetPageTitle: newProps.widgetPageTitle,
+ menuDisplayed: false,
};
}
@@ -555,45 +558,12 @@ export default class AppTile extends React.Component {
this.refs.appFrame.src = this.refs.appFrame.src;
}
- _getMenuOptions(ev) {
- // TODO: This block of code gets copy/pasted a lot. We should make that happen less.
- const menuOptions = {};
- const buttonRect = ev.target.getBoundingClientRect();
- // The window X and Y offsets are to adjust position when zoomed in to page
- const buttonLeft = buttonRect.left + window.pageXOffset;
- const buttonTop = buttonRect.top + window.pageYOffset;
- // Align the right edge of the menu to the left edge of the button
- menuOptions.right = window.innerWidth - buttonLeft;
- // Align the menu vertically on whichever side of the button has more
- // space available.
- if (buttonTop < window.innerHeight / 2) {
- menuOptions.top = buttonTop;
- } else {
- menuOptions.bottom = window.innerHeight - buttonTop;
- }
- return menuOptions;
- }
+ _onContextMenuClick = () => {
+ this.setState({ menuDisplayed: true });
+ };
- _onContextMenuClick = (ev) => {
- const WidgetContextMenu = sdk.getComponent('views.context_menus.WidgetContextMenu');
- const menuOptions = {
- ...this._getMenuOptions(ev),
-
- // A revoke handler is always required
- onRevokeClicked: this._onRevokeClicked,
- };
-
- const canUserModify = this._canUserModify();
- const showEditButton = Boolean(this._scalarClient && canUserModify);
- const showDeleteButton = (this.props.showDelete === undefined || this.props.showDelete) && canUserModify;
- const showPictureSnapshotButton = this._hasCapability('m.capability.screenshot') && this.props.show;
-
- if (showEditButton) menuOptions.onEditClicked = this._onEditClick;
- if (showDeleteButton) menuOptions.onDeleteClicked = this._onDeleteClick;
- if (showPictureSnapshotButton) menuOptions.onSnapshotClicked = this._onSnapshotClick;
- if (this.props.showReload) menuOptions.onReloadClicked = this._onReloadWidgetClick;
-
- createMenu(WidgetContextMenu, menuOptions);
+ _closeContextMenu = () => {
+ this.setState({ menuDisplayed: false });
};
render() {
@@ -601,7 +571,7 @@ export default class AppTile extends React.Component {
// Don't render widget if it is in the process of being deleted
if (this.state.deleting) {
- return
;
+ return
;
}
// Note that there is advice saying allow-scripts shouldn't be used with allow-same-origin
@@ -697,7 +667,31 @@ export default class AppTile extends React.Component {
mx_AppTileMenuBar_expanded: this.props.show,
});
- return (
+ let contextMenu;
+ if (this.state.menuDisplayed) {
+ const elementRect = this._contextMenuButton.current.getBoundingClientRect();
+
+ const canUserModify = this._canUserModify();
+ const showEditButton = Boolean(this._scalarClient && canUserModify);
+ const showDeleteButton = (this.props.showDelete === undefined || this.props.showDelete) && canUserModify;
+ const showPictureSnapshotButton = this._hasCapability('m.capability.screenshot') && this.props.show;
+
+ const WidgetContextMenu = sdk.getComponent('views.context_menus.WidgetContextMenu');
+ contextMenu = (
+
+
+
+ );
+ }
+
+ return
{ this.props.showMenubar &&
@@ -725,20 +719,24 @@ export default class AppTile extends React.Component {
onClick={this._onPopoutWidgetClick}
/> }
{ /* Context menu */ }
- {
}
}
{ appTileBody }
- );
+
+ { contextMenu }
+ ;
}
}
-AppTile.displayName ='AppTile';
+AppTile.displayName = 'AppTile';
AppTile.propTypes = {
id: PropTypes.string.isRequired,
diff --git a/src/components/views/elements/TagTile.js b/src/components/views/elements/TagTile.js
index c9afd487cb..636ea7a255 100644
--- a/src/components/views/elements/TagTile.js
+++ b/src/components/views/elements/TagTile.js
@@ -23,13 +23,14 @@ import classNames from 'classnames';
import { MatrixClient } from 'matrix-js-sdk';
import sdk from '../../../index';
import dis from '../../../dispatcher';
+import {_t} from '../../../languageHandler';
import { isOnlyCtrlOrCmdIgnoreShiftKeyEvent } from '../../../Keyboard';
import * as FormattingUtils from '../../../utils/FormattingUtils';
import FlairStore from '../../../stores/FlairStore';
import GroupStore from '../../../stores/GroupStore';
import TagOrderStore from '../../../stores/TagOrderStore';
-import {ContextMenu, toRightOf} from "../../structures/ContextualMenu";
+import {ContextMenu, ContextMenuButton, toRightOf} from "../../structures/ContextualMenu";
// A class for a child of TagPanel (possibly wrapped in a DNDTagTile) that represents
// a thing to click on for the user to filter the visible rooms in the RoomList to:
@@ -139,7 +140,6 @@ export default createReactClass({
render: function() {
const BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
- const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
const Tooltip = sdk.getComponent('elements.Tooltip');
const profile = this.state.profile || {};
const name = profile.name || this.props.tag;
@@ -178,14 +178,20 @@ export default createReactClass({
const elementRect = this._contextMenuButton.current.getBoundingClientRect();
const TagTileContextMenu = sdk.getComponent('context_menus.TagTileContextMenu');
contextMenu = (
-
+
);
}
return
-
+
-
+
{ contextMenu }
;
diff --git a/src/components/views/groups/GroupInviteTile.js b/src/components/views/groups/GroupInviteTile.js
index cfc50cc008..17e426a49d 100644
--- a/src/components/views/groups/GroupInviteTile.js
+++ b/src/components/views/groups/GroupInviteTile.js
@@ -22,9 +22,10 @@ import createReactClass from 'create-react-class';
import { MatrixClient } from 'matrix-js-sdk';
import sdk from '../../../index';
import dis from '../../../dispatcher';
+import {_t} from '../../../languageHandler';
import classNames from 'classnames';
import MatrixClientPeg from "../../../MatrixClientPeg";
-import {ContextMenu, toRightOf} from "../../structures/ContextualMenu";
+import {ContextMenu, ContextMenuButton, toRightOf} from "../../structures/ContextualMenu";
export default createReactClass({
displayName: 'GroupInviteTile',
@@ -124,9 +125,15 @@ export default createReactClass({
const badgeContent = badgeEllipsis ? '\u00B7\u00B7\u00B7' : '!';
const badge = (
-
+
{ badgeContent }
-
+
);
let tooltip;
@@ -146,7 +153,7 @@ export default createReactClass({
const elementRect = this._contextMenuButton.current.getBoundingClientRect();
const GroupInviteTileContextMenu = sdk.getComponent('context_menus.GroupInviteTileContextMenu');
contextMenu = (
-
+
);
diff --git a/src/components/views/messages/MessageActionBar.js b/src/components/views/messages/MessageActionBar.js
index d59e74623a..ba12bf21a0 100644
--- a/src/components/views/messages/MessageActionBar.js
+++ b/src/components/views/messages/MessageActionBar.js
@@ -16,50 +16,17 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import React, {useState, useEffect, useRef} from 'react';
+import React, {useEffect} from 'react';
import PropTypes from 'prop-types';
import { _t } from '../../../languageHandler';
import sdk from '../../../index';
import dis from '../../../dispatcher';
import Modal from '../../../Modal';
-import {ContextMenu} from '../../structures/ContextualMenu';
+import {aboveLeft, ContextMenu, ContextMenuButton, useContextMenu} from '../../structures/ContextualMenu';
import { isContentActionable, canEditContent } from '../../../utils/EventUtils';
import {RoomContext} from "../../structures/RoomView";
-const contextMenuProps = (elementRect) => {
- const menuOptions = {
- chevronFace: "none",
- };
-
- const buttonRight = elementRect.right + window.pageXOffset;
- const buttonBottom = elementRect.bottom + window.pageYOffset;
- const buttonTop = elementRect.top + window.pageYOffset;
- // Align the right edge of the menu to the right edge of the button
- menuOptions.right = window.innerWidth - buttonRight;
- // Align the menu vertically on whichever side of the button has more space available.
- if (buttonBottom < window.innerHeight / 2) {
- menuOptions.top = buttonBottom;
- } else {
- menuOptions.bottom = window.innerHeight - buttonTop;
- }
-
- return menuOptions;
-};
-
-const useContextMenu = () => {
- const _button = useRef(null);
- const [isOpen, setIsOpen] = useState(false);
- const open = () => {
- setIsOpen(true);
- };
- const close = () => {
- setIsOpen(false);
- };
-
- return [isOpen, _button, open, close, setIsOpen];
-};
-
const OptionsButton = ({mxEvent, getTile, getReplyThread, permalinkCreator, onFocusChange}) => {
const [menuDisplayed, _button, openMenu, closeMenu] = useContextMenu();
useEffect(() => {
@@ -86,7 +53,7 @@ const OptionsButton = ({mxEvent, getTile, getReplyThread, permalinkCreator, onFo
}
const buttonRect = _button.current.getBoundingClientRect();
- contextMenu =
+ contextMenu =
;
}
- const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
return
-
@@ -120,19 +85,17 @@ const ReactButton = ({mxEvent, reactions}) => {
if (menuDisplayed) {
const buttonRect = _button.current.getBoundingClientRect();
const ReactionPicker = sdk.getComponent('emojipicker.ReactionPicker');
- contextMenu =
+ contextMenu =
;
}
- const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
return
-
@@ -227,7 +190,7 @@ export default class MessageActionBar extends React.PureComponent {
getReplyThread={this.props.getReplyThread}
getTile={this.props.getTile}
permalinkCreator={this.props.permalinkCreator}
- onFocusChange={this.props.onFocusChange}
+ onFocusChange={this.onFocusChange}
/>
;
}
diff --git a/src/components/views/rooms/RoomTile.js b/src/components/views/rooms/RoomTile.js
index edd50d0330..3095981ccb 100644
--- a/src/components/views/rooms/RoomTile.js
+++ b/src/components/views/rooms/RoomTile.js
@@ -25,7 +25,7 @@ import dis from '../../../dispatcher';
import MatrixClientPeg from '../../../MatrixClientPeg';
import DMRoomMap from '../../../utils/DMRoomMap';
import sdk from '../../../index';
-import {ContextMenu, toRightOf} from '../../structures/ContextualMenu';
+import {ContextMenu, ContextMenuButton, toRightOf} from '../../structures/ContextualMenu';
import * as RoomNotifs from '../../../RoomNotifs';
import * as FormattingUtils from '../../../utils/FormattingUtils';
import ActiveRoomObserver from '../../../ActiveRoomObserver';
@@ -344,7 +344,12 @@ module.exports = createReactClass({
let contextMenuButton;
if (!MatrixClientPeg.get().isGuest()) {
contextMenuButton = (
-
+
);
}
@@ -381,7 +386,7 @@ module.exports = createReactClass({
const elementRect = this._contextMenuButton.current.getBoundingClientRect();
const RoomTileContextMenu = sdk.getComponent('context_menus.RoomTileContextMenu');
contextMenu = (
-
+
);