Avoid errant scroll on context menu hide

This commit is contained in:
trevor-signal 2025-02-19 12:22:48 -05:00 committed by GitHub
parent 78cfa7eca3
commit 1d44c70393
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 33 additions and 4 deletions

View file

@ -1,5 +1,5 @@
diff --git a/node_modules/react-contextmenu/modules/ContextMenu.js b/node_modules/react-contextmenu/modules/ContextMenu.js
index 2f88213..4cf584a 100644
index 2f88213..41e47ea 100644
--- a/node_modules/react-contextmenu/modules/ContextMenu.js
+++ b/node_modules/react-contextmenu/modules/ContextMenu.js
@@ -81,6 +81,11 @@ var ContextMenu = function (_AbstractMenu) {
@ -35,13 +35,15 @@ index 2f88213..4cf584a 100644
});
});
} else {
@@ -248,6 +259,14 @@ var ContextMenu = function (_AbstractMenu) {
@@ -248,6 +259,16 @@ var ContextMenu = function (_AbstractMenu) {
if (!_this2.menu) return;
_this2.menu.style.opacity = 0;
_this2.menu.style.pointerEvents = 'none';
+
+ // Return to the previous focus state when dismissing the menu, unless the
+ // menu option focused another element. This is important for keyboard mode.
+ if (_this2.props.avoidFocusRestoreOnBlur) return;
+
+ var isFocusWithinMenu = _this2.menu.contains(document.activeElement);
+ if (isFocusWithinMenu && _this2.previousFocus && _this2.previousFocus.focus) {
+ _this2.previousFocus.focus();
@ -139,3 +141,15 @@ index ad1dc70..c919be8 100644
this.subMenu.classList.remove(_helpers.cssClasses.menuVisible);
}
}
diff --git a/node_modules/react-contextmenu/src/index.d.ts b/node_modules/react-contextmenu/src/index.d.ts
index 753ce90..c5971a4 100644
--- a/node_modules/react-contextmenu/src/index.d.ts
+++ b/node_modules/react-contextmenu/src/index.d.ts
@@ -14,6 +14,7 @@ declare module "react-contextmenu" {
preventHideOnResize?: boolean,
preventHideOnScroll?: boolean,
style?: React.CSSProperties,
+ avoidFocusRestoreOnBlur?: boolean;
}
export interface ContextMenuTriggerProps {

View file

@ -62,6 +62,7 @@ const getCommonProps = (options: {
id: 'message-id',
conversationId: conversation.id,
i18n,
interactionMode: 'mouse',
isNextItemCallingNotification: false,
onOutgoingAudioCallInConversation: action(
'onOutgoingAudioCallInConversation'

View file

@ -38,6 +38,7 @@ import {
import { MINUTE } from '../../util/durations';
import { isMoreRecentThan } from '../../util/timestamp';
import { InAnotherCallTooltip } from './InAnotherCallTooltip';
import type { InteractionModeType } from '../../state/ducks/conversations';
export type PropsActionsType = {
onOutgoingAudioCallInConversation: (conversationId: string) => void;
@ -50,6 +51,7 @@ type PropsHousekeeping = {
i18n: LocalizerType;
id: string;
conversationId: string;
interactionMode: InteractionModeType;
isNextItemCallingNotification: boolean;
};
@ -120,6 +122,7 @@ export const CallingNotification: React.FC<PropsType> = React.memo(
<MessageContextMenu
i18n={i18n}
triggerId={props.id}
interactionMode={props.interactionMode}
onDeleteMessage={() => {
props.toggleDeleteMessagesModal({
conversationId: props.conversationId,

View file

@ -5,6 +5,7 @@ import React, { type RefObject } from 'react';
import { ContextMenu, MenuItem } from 'react-contextmenu';
import ReactDOM from 'react-dom';
import type { LocalizerType } from '../../types/I18N';
import type { InteractionModeType } from '../../state/ducks/conversations';
export type ContextMenuTriggerType = {
handleContextClick: (
@ -16,7 +17,7 @@ type MessageContextProps = {
i18n: LocalizerType;
triggerId: string;
shouldShowAdditional: boolean;
interactionMode: InteractionModeType;
onDownload: (() => void) | undefined;
onEdit: (() => void) | undefined;
onReplyToMessage: (() => void) | undefined;
@ -33,6 +34,7 @@ export const MessageContextMenu = ({
i18n,
triggerId,
shouldShowAdditional,
interactionMode,
onDownload,
onEdit,
onReplyToMessage,
@ -46,7 +48,14 @@ export const MessageContextMenu = ({
onDeleteMessage,
}: MessageContextProps): JSX.Element => {
const menu = (
<ContextMenu id={triggerId}>
// We avoid restoring focus on this context menu because it is not intended for
// keyboard use and restoring focus to the message could cause an unwanted scroll
<ContextMenu
id={triggerId}
// In keyboard mode, we do want to restore focus to the message; the message is very
// likely already scrolled into view in this case.
avoidFocusRestoreOnBlur={interactionMode !== 'keyboard'}
>
{shouldShowAdditional && (
<>
{onDownload && (

View file

@ -286,6 +286,7 @@ export const TimelineItem = memo(function TimelineItem({
<CallingNotification
id={id}
conversationId={conversationId}
interactionMode={reducedProps.interactionMode}
i18n={i18n}
isNextItemCallingNotification={isNextItemCallingNotification}
onOutgoingAudioCallInConversation={onOutgoingAudioCallInConversation}

View file

@ -365,6 +365,7 @@ export function TimelineMessage(props: Props): JSX.Element {
i18n={i18n}
triggerId={triggerId}
shouldShowAdditional={shouldShowAdditional}
interactionMode={props.interactionMode}
onDownload={handleDownload}
onEdit={
canEditMessage