Ensure composition input is focused when clicking to edit or reply to message

This commit is contained in:
trevor-signal
2026-01-06 17:00:18 -05:00
committed by GitHub
parent d2ffbab7a1
commit 90e751141f
5 changed files with 39 additions and 4 deletions

View File

@@ -238,6 +238,7 @@ export namespace AxoContextMenu {
className={AxoBaseMenu.menuContentStyles}
alignOffset={-6}
collisionPadding={6}
onCloseAutoFocus={props.onCloseAutoFocus}
>
{props.children}
</ContextMenu.Content>

View File

@@ -190,6 +190,7 @@ export namespace AxoDropdownMenu {
*/
export const Content: FC<ContentProps> = memo(props => {
const { context, labelId, descriptionId } = useCreateAriaLabellingContext();
const { open } = useStrictContext(RootContext);
return (
<AriaLabellingProvider value={context}>
<DropdownMenu.Portal>
@@ -200,6 +201,9 @@ export namespace AxoDropdownMenu {
className={AxoBaseMenu.menuContentStyles}
aria-labelledby={labelId}
aria-describedby={descriptionId}
onCloseAutoFocus={props.onCloseAutoFocus}
// @ts-expect-error -- React/TS doesn't know about inert
inert={open ? undefined : 'true'}
>
{props.children}
</DropdownMenu.Content>

View File

@@ -201,6 +201,7 @@ export namespace AxoBaseMenu {
*/
export type MenuContentProps = Readonly<{
onCloseAutoFocus?: (e: Event) => void;
children: ReactNode;
}>;

View File

@@ -1,7 +1,7 @@
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React, { type ReactNode } from 'react';
import React, { useRef, type ReactNode } from 'react';
import type { LocalizerType } from '../../types/I18N.std.js';
import { AxoMenuBuilder } from '../../axo/AxoMenuBuilder.dom.js';
@@ -50,12 +50,20 @@ export function MessageContextMenu({
onUnpinMessage,
children,
}: MessageContextMenuProps): JSX.Element {
const shouldReturnFocusToTrigger = useRef(true);
return (
<AxoMenuBuilder.Root renderer={renderer} onOpenChange={onOpenChange}>
<AxoMenuBuilder.Trigger disabled={disabled}>
{children}
</AxoMenuBuilder.Trigger>
<AxoMenuBuilder.Content>
<AxoMenuBuilder.Content
onCloseAutoFocus={e => {
if (!shouldReturnFocusToTrigger.current) {
e.preventDefault();
}
}}
>
{shouldShowAdditional && (
<>
{onDownload && (
@@ -64,7 +72,14 @@ export function MessageContextMenu({
</AxoMenuBuilder.Item>
)}
{onReplyToMessage && (
<AxoMenuBuilder.Item symbol="reply" onSelect={onReplyToMessage}>
<AxoMenuBuilder.Item
symbol="reply"
onSelect={() => {
// onReplyToMessage will focus the quill input
shouldReturnFocusToTrigger.current = false;
onReplyToMessage();
}}
>
{i18n('icu:MessageContextMenu__reply')}
</AxoMenuBuilder.Item>
)}
@@ -86,7 +101,14 @@ export function MessageContextMenu({
</AxoMenuBuilder.Item>
)}
{onEdit && (
<AxoMenuBuilder.Item symbol="pencil" onSelect={onEdit}>
<AxoMenuBuilder.Item
symbol="pencil"
onSelect={() => {
// onEdit will focus the quill input
shouldReturnFocusToTrigger.current = false;
onEdit();
}}
>
{i18n('icu:edit')}
</AxoMenuBuilder.Item>
)}

View File

@@ -2342,5 +2342,12 @@
"line": " const listenerRef = useRef(listener);",
"reasonCategory": "usageTrusted",
"updated": "2025-12-09T15:37:49.757Z"
},
{
"rule": "React-useRef",
"path": "ts/components/conversation/MessageContextMenu.dom.tsx",
"line": " const shouldReturnFocusToTrigger = useRef(true);",
"reasonCategory": "usageTrusted",
"updated": "2025-12-19T16:03:53.849Z"
}
]