Skip to content

Commit b427e2d

Browse files
[A11y][Chat] Fix an issue where keyboard focus was lost after message is edited (#5530)
1 parent f76b857 commit b427e2d

File tree

4 files changed

+51
-17
lines changed

4 files changed

+51
-17
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"type": "patch",
3+
"area": "fix",
4+
"workstream": "A11y",
5+
"comment": "Fix an issue where keyboard focus was lost after message is edited",
6+
"packageName": "@azure/communication-react",
7+
"email": "[email protected]",
8+
"dependentChangeType": "patch"
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"type": "patch",
3+
"area": "fix",
4+
"workstream": "A11y",
5+
"comment": "Fix an issue where keyboard focus was lost after message is edited",
6+
"packageName": "@azure/communication-react",
7+
"email": "[email protected]",
8+
"dependentChangeType": "patch"
9+
}

packages/react-components/src/components/ChatMessage/MyMessageComponents/ChatMyMessageComponent.tsx

+22-14
Original file line numberDiff line numberDiff line change
@@ -108,13 +108,15 @@ export type ChatMyMessageComponentProps = {
108108
onInsertInlineImage?: (imageAttributes: Record<string, string>, messageId: string) => void;
109109
/* @conditional-compile-remove(rich-text-editor-image-upload) */
110110
inlineImagesWithProgress?: AttachmentMetadataInProgress[];
111+
// Optional callback called when editing is complete (submitted or cancelled).
112+
onEditComplete?: () => void;
111113
};
112114

113115
/**
114116
* @private
115117
*/
116118
export const ChatMyMessageComponent = (props: ChatMyMessageComponentProps): JSX.Element => {
117-
const { onDeleteMessage, onSendMessage, message } = props;
119+
const { onDeleteMessage, onSendMessage, message, onEditComplete, onCancelEditMessage, onUpdateMessage } = props;
118120
const [isEditing, setIsEditing] = useState(false);
119121

120122
const onEditClick = useCallback(() => setIsEditing(true), [setIsEditing]);
@@ -169,28 +171,34 @@ export const ChatMyMessageComponent = (props: ChatMyMessageComponentProps): JSX.
169171
if (`attachments` in message && attachments) {
170172
message.attachments = attachments;
171173
}
172-
props.onUpdateMessage &&
173-
message.messageId &&
174-
(await props.onUpdateMessage(
175-
message.messageId,
176-
text,
177-
/* @conditional-compile-remove(file-sharing-acs) */
178-
{ attachments: attachments }
179-
));
174+
await onUpdateMessage?.(
175+
message.messageId,
176+
text,
177+
/* @conditional-compile-remove(file-sharing-acs) */
178+
{ attachments: attachments }
179+
);
180180
setIsEditing(false);
181+
onEditComplete?.();
181182
},
182-
[message, props]
183+
[message, onEditComplete, onUpdateMessage]
183184
);
185+
186+
const onCancelHandler = useCallback(
187+
(messageId: string) => {
188+
onCancelEditMessage?.(messageId);
189+
setIsEditing(false);
190+
onEditComplete?.();
191+
},
192+
[onEditComplete, onCancelEditMessage]
193+
);
194+
184195
if (isEditing && message.messageType === 'chat') {
185196
return (
186197
<ChatMessageComponentAsEditBoxPicker
187198
message={message}
188199
strings={props.strings}
189200
onSubmit={onSubmitHandler}
190-
onCancel={(messageId) => {
191-
props.onCancelEditMessage && props.onCancelEditMessage(messageId);
192-
setIsEditing(false);
193-
}}
201+
onCancel={onCancelHandler}
194202
/* @conditional-compile-remove(mention) */
195203
mentionLookupOptions={props.mentionOptions?.lookupOptions}
196204
/* @conditional-compile-remove(rich-text-editor) */

packages/react-components/src/components/ChatMessage/MyMessageComponents/FluentChatMyMessageComponent.tsx

+11-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Licensed under the MIT License.
33

44
import { MessageStatus, _formatString } from '@internal/acs-ui-common';
5-
import React, { useCallback, useMemo } from 'react';
5+
import React, { useCallback, useMemo, useRef } from 'react';
66
import { MessageProps, _ChatMessageProps } from '../../MessageThread';
77
import { ChatMessage } from '../../../types';
88
/* @conditional-compile-remove(data-loss-prevention) */
@@ -59,6 +59,11 @@ export const FluentChatMyMessageComponent = (props: FluentChatMessageComponentWr
5959
onInsertInlineImage
6060
} = props;
6161
const chatMessageRenderStyles = useChatMessageRenderStyles();
62+
const fluentMessageBodyRef = useRef<HTMLDivElement>(null);
63+
64+
const onEditComplete = useCallback(() => {
65+
fluentMessageBodyRef.current?.focus();
66+
}, []);
6267

6368
// To rerender the defaultChatMessageRenderer if app running across days(every new day chat time stamp
6469
// needs to be regenerated), the dependency on "new Date().toDateString()"" is added.
@@ -71,6 +76,7 @@ export const FluentChatMyMessageComponent = (props: FluentChatMessageComponentWr
7176
return (
7277
<ChatMyMessageComponent
7378
{...messageProps}
79+
onEditComplete={onEditComplete}
7480
onRenderAttachmentDownloads={onRenderAttachmentDownloads}
7581
strings={messageProps.strings}
7682
message={messageProps.message}
@@ -127,7 +133,8 @@ export const FluentChatMyMessageComponent = (props: FluentChatMessageComponentWr
127133
/* @conditional-compile-remove(rich-text-editor-image-upload) */
128134
onInsertInlineImage,
129135
/* @conditional-compile-remove(rich-text-editor-image-upload) */
130-
inlineImagesWithProgress
136+
inlineImagesWithProgress,
137+
onEditComplete
131138
]
132139
);
133140

@@ -190,7 +197,8 @@ export const FluentChatMyMessageComponent = (props: FluentChatMessageComponentWr
190197

191198
const myMessageBodyProps = useMemo(() => {
192199
return {
193-
className: mergeClasses(chatMessageRenderStyles.bodyCommon, chatMessageRenderStyles.bodyMyMessage)
200+
className: mergeClasses(chatMessageRenderStyles.bodyCommon, chatMessageRenderStyles.bodyMyMessage),
201+
ref: fluentMessageBodyRef
194202
};
195203
}, [chatMessageRenderStyles.bodyCommon, chatMessageRenderStyles.bodyMyMessage]);
196204

0 commit comments

Comments
 (0)