Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 4ddc97d

Browse files
committed
Fix thread list context menu roving
1 parent 7c226b9 commit 4ddc97d

File tree

2 files changed

+42
-24
lines changed

2 files changed

+42
-24
lines changed

src/components/views/context_menus/ThreadListContextMenu.tsx

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,34 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
import React, { useCallback, useEffect, useState } from "react";
17+
import React, { RefObject, useCallback, useEffect } from "react";
1818
import { MatrixEvent } from "matrix-js-sdk/src";
1919

2020
import { ButtonEvent } from "../elements/AccessibleButton";
2121
import dis from '../../../dispatcher/dispatcher';
2222
import { Action } from "../../../dispatcher/actions";
2323
import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
2424
import { copyPlaintext } from "../../../utils/strings";
25-
import { ChevronFace, ContextMenuTooltipButton } from "../../structures/ContextMenu";
25+
import { ChevronFace, ContextMenuTooltipButton, useContextMenu } from "../../structures/ContextMenu";
2626
import { _t } from "../../../languageHandler";
2727
import IconizedContextMenu, { IconizedContextMenuOption, IconizedContextMenuOptionList } from "./IconizedContextMenu";
2828
import { WidgetLayoutStore } from "../../../stores/widgets/WidgetLayoutStore";
2929
import { MatrixClientPeg } from "../../../MatrixClientPeg";
30+
import { useRovingTabIndex } from "../../../accessibility/RovingTabIndex";
3031

3132
interface IProps {
3233
mxEvent: MatrixEvent;
3334
permalinkCreator: RoomPermalinkCreator;
3435
onMenuToggle?: (open: boolean) => void;
3536
}
3637

38+
interface IExtendedProps extends IProps {
39+
// Props for making the button into a roving one
40+
tabIndex?: number;
41+
inputRef?: RefObject<HTMLElement>;
42+
onFocus?(): void;
43+
}
44+
3745
const contextMenuBelow = (elementRect: DOMRect) => {
3846
// align the context menu's icons with the icon which opened the context menu
3947
const left = elementRect.left + window.pageXOffset + elementRect.width;
@@ -42,11 +50,27 @@ const contextMenuBelow = (elementRect: DOMRect) => {
4250
return { left, top, chevronFace };
4351
};
4452

45-
const ThreadListContextMenu: React.FC<IProps> = ({ mxEvent, permalinkCreator, onMenuToggle }) => {
46-
const [optionsPosition, setOptionsPosition] = useState(null);
47-
const closeThreadOptions = useCallback(() => {
48-
setOptionsPosition(null);
49-
}, []);
53+
export const RovingThreadListContextMenu: React.FC<IProps> = (props) => {
54+
const [onFocus, isActive, ref] = useRovingTabIndex();
55+
56+
return <ThreadListContextMenu
57+
{...props}
58+
onFocus={onFocus}
59+
tabIndex={isActive ? 0 : -1}
60+
inputRef={ref}
61+
/>;
62+
};
63+
64+
const ThreadListContextMenu: React.FC<IExtendedProps> = ({
65+
mxEvent,
66+
permalinkCreator,
67+
onMenuToggle,
68+
onFocus,
69+
inputRef,
70+
...props
71+
}) => {
72+
const [menuDisplayed, _ref, openMenu, closeThreadOptions] = useContextMenu();
73+
const button = inputRef ?? _ref; // prefer the ref we receive via props in case we are being controlled
5074

5175
const viewInRoom = useCallback((evt: ButtonEvent): void => {
5276
evt.preventDefault();
@@ -68,37 +92,31 @@ const ThreadListContextMenu: React.FC<IProps> = ({ mxEvent, permalinkCreator, on
6892
closeThreadOptions();
6993
}, [mxEvent, closeThreadOptions, permalinkCreator]);
7094

71-
const toggleOptionsMenu = useCallback((ev: ButtonEvent): void => {
72-
if (!!optionsPosition) {
73-
closeThreadOptions();
74-
} else {
75-
const position = ev.currentTarget.getBoundingClientRect();
76-
setOptionsPosition(position);
77-
}
78-
}, [closeThreadOptions, optionsPosition]);
79-
8095
useEffect(() => {
8196
if (onMenuToggle) {
82-
onMenuToggle(!!optionsPosition);
97+
onMenuToggle(menuDisplayed);
8398
}
84-
}, [optionsPosition, onMenuToggle]);
99+
onFocus?.();
100+
}, [menuDisplayed, onMenuToggle, onFocus]);
85101

86102
const isMainSplitTimelineShown = !WidgetLayoutStore.instance.hasMaximisedWidget(
87103
MatrixClientPeg.get().getRoom(mxEvent.getRoomId()),
88104
);
89105
return <React.Fragment>
90106
<ContextMenuTooltipButton
107+
{...props}
91108
className="mx_MessageActionBar_maskButton mx_MessageActionBar_optionsButton"
92-
onClick={toggleOptionsMenu}
109+
onClick={openMenu}
93110
title={_t("Thread options")}
94-
isExpanded={!!optionsPosition}
111+
isExpanded={menuDisplayed}
112+
inputRef={button}
95113
/>
96-
{ !!optionsPosition && (<IconizedContextMenu
114+
{ menuDisplayed && (<IconizedContextMenu
97115
onFinished={closeThreadOptions}
98116
className="mx_RoomTile_contextMenu"
99117
compact
100118
rightAligned
101-
{...contextMenuBelow(optionsPosition)}
119+
{...contextMenuBelow(button.current.getBoundingClientRect())}
102120
>
103121
<IconizedContextMenuOptionList>
104122
{ isMainSplitTimelineShown &&

src/components/views/rooms/EventTile.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ import { MediaEventHelper } from "../../../utils/MediaEventHelper";
6666
import Toolbar from '../../../accessibility/Toolbar';
6767
import { POLL_START_EVENT_TYPE } from '../../../polls/consts';
6868
import { RovingAccessibleTooltipButton } from '../../../accessibility/roving/RovingAccessibleTooltipButton';
69-
import ThreadListContextMenu from '../context_menus/ThreadListContextMenu';
69+
import { RovingThreadListContextMenu } from '../context_menus/ThreadListContextMenu';
7070

7171
const eventTileTypes = {
7272
[EventType.RoomMessage]: 'messages.MessageEvent',
@@ -1382,7 +1382,7 @@ export default class EventTile extends React.Component<IProps, IState> {
13821382
onClick={() => dispatchShowThreadEvent(this.props.mxEvent)}
13831383
key="thread"
13841384
/>
1385-
<ThreadListContextMenu
1385+
<RovingThreadListContextMenu
13861386
mxEvent={this.props.mxEvent}
13871387
permalinkCreator={this.props.permalinkCreator}
13881388
onMenuToggle={this.onActionBarFocusChange}

0 commit comments

Comments
 (0)