4
4
import { Text , mergeStyles } from '@fluentui/react' ;
5
5
import { ChatMyMessage } from '@fluentui-contrib/react-chat' ;
6
6
import { _formatString } from '@internal/acs-ui-common' ;
7
- import React , { useCallback , useMemo , useRef , useState } from 'react' ;
7
+ import React , { useCallback , useEffect , useMemo , useRef , useState } from 'react' ;
8
8
import {
9
9
chatMessageDateStyle ,
10
10
chatMessageFailedTagStyle ,
@@ -28,7 +28,11 @@ import { useLocale } from '../../../localization';
28
28
import { MentionDisplayOptions } from '../../MentionPopover' ;
29
29
import { createStyleFromV8Style } from '../../styles/v8StyleShim' ;
30
30
import { mergeClasses } from '@fluentui/react-components' ;
31
- import { useChatMyMessageStyles , useChatMessageCommonStyles } from '../../styles/MessageThread.styles' ;
31
+ import {
32
+ useChatMyMessageStyles ,
33
+ useChatMessageCommonStyles ,
34
+ chatMyMessageActionMenuClassName
35
+ } from '../../styles/MessageThread.styles' ;
32
36
import {
33
37
generateCustomizedTimestamp ,
34
38
generateDefaultTimestamp ,
@@ -53,6 +57,8 @@ type ChatMyMessageComponentAsMessageBubbleProps = {
53
57
* Whether the status indicator for each message is displayed or not.
54
58
*/
55
59
showMessageStatus ?: boolean ;
60
+ // Focus on the message body after the message is edited
61
+ shouldFocusFluentMessageBody : boolean ;
56
62
remoteParticipantsCount ?: number ;
57
63
onActionButtonClick : (
58
64
message : ChatMessage ,
@@ -116,7 +122,8 @@ const MessageBubble = (props: ChatMyMessageComponentAsMessageBubbleProps): JSX.E
116
122
mentionDisplayOptions,
117
123
onDisplayDateTimeString,
118
124
onRenderAttachmentDownloads,
119
- actionsForAttachment
125
+ actionsForAttachment,
126
+ shouldFocusFluentMessageBody
120
127
} = props ;
121
128
122
129
const formattedTimestamp = useMemo ( ( ) => {
@@ -166,6 +173,15 @@ const MessageBubble = (props: ChatMyMessageComponentAsMessageBubbleProps): JSX.E
166
173
theme
167
174
} ) ;
168
175
176
+ useEffect ( ( ) => {
177
+ if ( shouldFocusFluentMessageBody ) {
178
+ // set focus in the next render cycle to avoid focus being stolen by other components
179
+ setTimeout ( ( ) => {
180
+ messageRef . current ?. focus ( ) ;
181
+ } ) ;
182
+ }
183
+ } , [ shouldFocusFluentMessageBody ] ) ;
184
+
169
185
const onActionFlyoutDismiss = useCallback ( ( ) : void => {
170
186
// When the flyout dismiss is called, since we control if the action flyout is visible
171
187
// or not we need to set the target to undefined here to actually hide the action flyout
@@ -185,19 +201,57 @@ const MessageBubble = (props: ChatMyMessageComponentAsMessageBubbleProps): JSX.E
185
201
}
186
202
} , [ message , messageStatus , strings . editedTag , strings . failToSendTag , theme ] ) ;
187
203
204
+ const isBlockedMessage =
205
+ false || /* @conditional -compile-remove(data-loss-prevention) */ message . messageType === 'blocked' ;
206
+ const chatMyMessageStyles = useChatMyMessageStyles ( ) ;
207
+ const chatMessageCommonStyles = useChatMessageCommonStyles ( ) ;
208
+
209
+ const attached = message . attached === true ? 'center' : message . attached === 'bottom' ? 'bottom' : 'top' ;
210
+
211
+ const getActionsMenu = useCallback ( ( ) => {
212
+ return (
213
+ < div
214
+ className = { mergeClasses (
215
+ // add the static class name to use it in useChatMyMessageStyles
216
+ chatMyMessageActionMenuClassName ,
217
+ chatMyMessageStyles . menu ,
218
+ // Make actions menu visible when the message is focused or the flyout is shown
219
+ focused || chatMessageActionFlyoutTarget ?. current
220
+ ? chatMyMessageStyles . menuVisible
221
+ : chatMyMessageStyles . menuHidden
222
+ ) }
223
+ >
224
+ { actionMenuProps ?. children }
225
+ </ div >
226
+ ) ;
227
+ } , [
228
+ actionMenuProps ?. children ,
229
+ chatMessageActionFlyoutTarget ,
230
+ chatMyMessageStyles . menu ,
231
+ chatMyMessageStyles . menuHidden ,
232
+ chatMyMessageStyles . menuVisible ,
233
+ focused
234
+ ] ) ;
235
+
188
236
const getContent = useCallback ( ( ) => {
189
- return getMessageBubbleContent (
190
- message ,
191
- strings ,
192
- userId ,
193
- inlineImageOptions ,
194
- /* @conditional -compile-remove(mention) */
195
- mentionDisplayOptions ,
196
- onRenderAttachmentDownloads ,
197
- actionsForAttachment
237
+ return (
238
+ < div >
239
+ { getMessageBubbleContent (
240
+ message ,
241
+ strings ,
242
+ userId ,
243
+ inlineImageOptions ,
244
+ /* @conditional -compile-remove(mention) */
245
+ mentionDisplayOptions ,
246
+ onRenderAttachmentDownloads ,
247
+ actionsForAttachment
248
+ ) }
249
+ { getActionsMenu ( ) }
250
+ </ div >
198
251
) ;
199
252
} , [
200
253
actionsForAttachment ,
254
+ getActionsMenu ,
201
255
inlineImageOptions ,
202
256
/* @conditional -compile-remove(mention) */ mentionDisplayOptions ,
203
257
message ,
@@ -206,12 +260,6 @@ const MessageBubble = (props: ChatMyMessageComponentAsMessageBubbleProps): JSX.E
206
260
userId
207
261
] ) ;
208
262
209
- const isBlockedMessage =
210
- false || /* @conditional -compile-remove(data-loss-prevention) */ message . messageType === 'blocked' ;
211
- const chatMyMessageStyles = useChatMyMessageStyles ( ) ;
212
- const chatMessageCommonStyles = useChatMessageCommonStyles ( ) ;
213
-
214
- const attached = message . attached === true ? 'center' : message . attached === 'bottom' ? 'bottom' : 'top' ;
215
263
const chatMessage = (
216
264
< >
217
265
< div key = { props . message . messageId } >
@@ -271,17 +319,6 @@ const MessageBubble = (props: ChatMyMessageComponentAsMessageBubbleProps): JSX.E
271
319
</ Text >
272
320
}
273
321
details = { getMessageDetails ( ) }
274
- actions = { {
275
- children : actionMenuProps ?. children ,
276
- className : mergeClasses (
277
- chatMyMessageStyles . menu ,
278
- // Make actions menu visible when the message is focused or the flyout is shown
279
- focused || chatMessageActionFlyoutTarget ?. current
280
- ? chatMyMessageStyles . menuVisible
281
- : chatMyMessageStyles . menuHidden ,
282
- attached !== 'top' ? chatMyMessageStyles . menuAttached : undefined
283
- )
284
- } }
285
322
onTouchStart = { ( ) => setWasInteractionByTouch ( true ) }
286
323
onPointerDown = { ( ) => setWasInteractionByTouch ( false ) }
287
324
onKeyDown = { ( ) => setWasInteractionByTouch ( false ) }
0 commit comments