11/* eslint-disable complexity */
22import { isRoomFederated , isRoomNativeFederated , type IMessage , type ISubscription } from '@rocket.chat/core-typings' ;
33import { useContentBoxSize , useStableCallback , useMediaQuery , useSafeRefCallback } from '@rocket.chat/fuselage-hooks' ;
4- import {
5- MessageComposerAction ,
6- MessageComposerToolbarActions ,
7- MessageComposer ,
8- MessageComposerToolbar ,
9- MessageComposerActionsDivider ,
10- MessageComposerToolbarSubmit ,
11- MessageComposerButton ,
12- MessageComposerInputExpandable ,
13- } from '@rocket.chat/ui-composer' ;
4+ import { MessageComposerInputExpandable } from '@rocket.chat/ui-composer' ;
145import { useTranslation , useUserPreference , useLayout , useSetting } from '@rocket.chat/ui-contexts' ;
156import { useMutation } from '@tanstack/react-query' ;
167import type { MouseEvent , ClipboardEvent , ChangeEvent } from 'react' ;
178import { memo , useRef , useReducer , useCallback , useSyncExternalStore } from 'react' ;
189
19- import MessageBoxActionsToolbar from './MessageBoxActionsToolbar' ;
20- import MessageBoxFormattingToolbar from './MessageBoxFormattingToolbar' ;
21- import MessageBoxHint from './MessageBoxHint' ;
22- import MessageBoxReplies from './MessageBoxReplies' ;
10+ import MessageBoxBase from './MessageBoxBase' ;
2311import MessageComposerFiles from './MessageComposerFiles' ;
12+ import { emptySubscribe , getEmptyFalse , getEmptyArray , handleFormattingShortcut } from './messageBoxHelpers' ;
2413import { handleSelectionWrapping } from './wrapSelection' ;
2514import { emoji } from '../../../../../app/emoji/client' ;
2615import { createComposerAPI } from '../../../../../app/ui-message/client/messageBox/createComposerAPI' ;
27- import type { FormattingButton } from '../../../../../app/ui-message/client/messageBox/messageBoxFormatting' ;
2816import { formattingButtons } from '../../../../../app/ui-message/client/messageBox/messageBoxFormatting' ;
29- import { getImageExtensionFromMime } from '../../../../../lib/getImageExtensionFromMime' ;
3017import { useFormatDateAndTime } from '../../../../hooks/useFormatDateAndTime' ;
3118import { useIsFederationEnabled } from '../../../../hooks/useIsFederationEnabled' ;
32- import type { ComposerAPI } from '../../../../lib/chats/ChatAPI' ;
3319import { roomCoordinator } from '../../../../lib/rooms/roomCoordinator' ;
3420import { keyCodes } from '../../../../lib/utils/keyCodes' ;
3521import { Subscriptions } from '../../../../stores' ;
36- import AudioMessageRecorder from '../../../composer/AudioMessageRecorder' ;
37- import VideoMessageRecorder from '../../../composer/VideoMessageRecorder' ;
3822import { useFileUpload } from '../../body/hooks/useFileUpload' ;
3923import { useChat } from '../../contexts/ChatContext' ;
4024import { useComposerPopupOptions } from '../../contexts/ComposerPopupContext' ;
4125import { useRoom , useRoomSubscription } from '../../contexts/RoomContext' ;
42- import ComposerBoxPopup from '../ComposerBoxPopup' ;
43- import ComposerBoxPopupPreview from '../ComposerBoxPopupPreview' ;
44- import ComposerUserActionIndicator from '../ComposerUserActionIndicator' ;
4526import { useAutoGrow } from '../RoomComposer/hooks/useAutoGrow' ;
4627import { useComposerBoxPopup } from '../hooks/useComposerBoxPopup' ;
4728import { useEnablePopupPreview } from '../hooks/useEnablePopupPreview' ;
4829import { useMessageComposerMergedRefs } from '../hooks/useMessageComposerMergedRefs' ;
4930import { useDraft } from './hooks/useDraft' ;
5031import { useMessageBoxAutoFocus } from './hooks/useMessageBoxAutoFocus' ;
5132import { useMessageBoxPlaceholder } from './hooks/useMessageBoxPlaceholder' ;
33+ import { getImageExtensionFromMime } from '../../../../../lib/getImageExtensionFromMime' ;
5234
5335const reducer = ( _ : unknown , event : ChangeEvent < HTMLInputElement > ) : boolean => {
5436 const target = event . target as HTMLInputElement ;
5537
5638 return Boolean ( target . value . trim ( ) ) ;
5739} ;
5840
59- const handleFormattingShortcut = ( event : KeyboardEvent , formattingButtons : FormattingButton [ ] , composer : ComposerAPI ) => {
60- const isMacOS = navigator . platform . indexOf ( 'Mac' ) !== - 1 ;
61- const isCmdOrCtrlPressed = ( isMacOS && event . metaKey ) || ( ! isMacOS && event . ctrlKey ) ;
62-
63- if ( ! isCmdOrCtrlPressed ) {
64- return false ;
65- }
66-
67- const key = event . key . toLowerCase ( ) ;
68-
69- const formatter = formattingButtons . find ( ( formatter ) => 'command' in formatter && formatter . command === key ) ;
70-
71- if ( ! formatter || ! ( 'pattern' in formatter ) ) {
72- return false ;
73- }
74-
75- composer . wrapSelection ( formatter . pattern ) ;
76- return true ;
77- } ;
78-
79- const emptySubscribe = ( ) => ( ) => undefined ;
80- const getEmptyFalse = ( ) => false ;
81- const a : any [ ] = [ ] ;
82- const getEmptyArray = ( ) => a ;
83-
8441export type MessageBoxProps = {
8542 tmid ?: IMessage [ '_id' ] ;
8643 onSend ?: ( params : { value : string ; tshow ?: boolean ; previewUrls ?: string [ ] ; isSlashCommandAllowed ?: boolean } ) => Promise < void > ;
8744 onJoin ?: ( ) => Promise < void > ;
8845 onResize ?: ( ) => void ;
8946 onTyping ?: ( ) => void ;
47+ onUploadFiles ?: ( files : File [ ] ) => void ;
9048 onEscape ?: ( ) => void ;
9149 onNavigateToPreviousMessage ?: ( ) => void ;
9250 onNavigateToNextMessage ?: ( ) => void ;
@@ -103,6 +61,7 @@ const MessageBox = ({
10361 onJoin,
10462 onNavigateToNextMessage,
10563 onNavigateToPreviousMessage,
64+ onUploadFiles,
10665 onEscape,
10766 onTyping,
10867 tshow,
@@ -370,7 +329,7 @@ const MessageBox = ({
370329
371330 if ( files . length ) {
372331 event . preventDefault ( ) ;
373- handleUploadFiles ?. ( files ) ;
332+ ( onUploadFiles ?? handleUploadFiles ) ( files ) ;
374333 }
375334 } ) ;
376335
@@ -418,45 +377,33 @@ const MessageBox = ({
418377 const shouldPopupPreview = useEnablePopupPreview ( popup . filter , popup . option ) ;
419378
420379 return (
421- < >
422- { chat . composer ?. quotedMessages && < MessageBoxReplies /> }
423- { shouldPopupPreview && popup . option && (
424- < ComposerBoxPopup
425- select = { popup . select }
426- items = { popup . items }
427- focused = { popup . focused }
428- title = { popup . option . title }
429- renderItem = { popup . option . renderItem }
430- />
431- ) }
432- { /*
433- SlashCommand Preview popup works in a weird way
434- There is only one trigger for all the commands: "/"
435- After that we need to the slashcommand list and check if the command exists and provide the preview
436- if not the query is `suspend` which means the slashcommand is not found or doesn't have a preview
437- */ }
438- { popup . option ?. preview && (
439- < ComposerBoxPopupPreview
440- select = { popup . select }
441- items = { popup . items as any }
442- focused = { popup . focused as any }
443- title = { popup . option . title }
444- renderItem = { popup . option . renderItem }
445- ref = { popup . commandsRef }
446- rid = { room . _id }
447- tmid = { tmid }
448- suspended = { popup . suspended }
449- />
450- ) }
451- < MessageBoxHint
452- isEditing = { isEditing }
453- e2eEnabled = { e2eEnabled }
454- unencryptedMessagesAllowed = { unencryptedMessagesAllowed }
455- isMobile = { isMobile }
456- />
457- { isRecordingVideo && < VideoMessageRecorder reference = { messageComposerRef } rid = { room . _id } tmid = { tmid } /> }
458- < MessageComposer ref = { messageComposerRef } variant = { isEditing ? 'editing' : undefined } >
459- { isRecordingAudio && < AudioMessageRecorder rid = { room . _id } isMicrophoneDenied = { isMicrophoneDenied } /> }
380+ < MessageBoxBase
381+ rid = { room . _id }
382+ tmid = { tmid }
383+ composer = { chat . composer }
384+ messageComposerRef = { messageComposerRef }
385+ popup = { popup }
386+ shouldPopupPreview = { shouldPopupPreview }
387+ isEditing = { isEditing }
388+ isRecording = { isRecording }
389+ isRecordingAudio = { isRecordingAudio }
390+ isRecordingVideo = { isRecordingVideo }
391+ isMicrophoneDenied = { isMicrophoneDenied }
392+ formatters = { formatters }
393+ canSend = { canSend }
394+ useEmojis = { useEmojis }
395+ sendEnabled = { canSend && ! isUploading && ! isProcessingUploads && ( typing || isEditing || hasUploads ) }
396+ sendActive = { typing || isEditing || hasUploads }
397+ inlineSize = { sizes . inlineSize }
398+ e2eEnabled = { e2eEnabled }
399+ unencryptedMessagesAllowed = { unencryptedMessagesAllowed }
400+ isMobile = { isMobile }
401+ joinPending = { joinMutation . isPending }
402+ onEmojiClick = { handleOpenEmojiPicker }
403+ onSend = { handleSendMessage }
404+ onJoin = { onJoin }
405+ closeEditing = { closeEditing }
406+ input = {
460407 < MessageComposerInputExpandable
461408 dimensions = { sizes }
462409 ref = { mergedRefs }
@@ -469,58 +416,9 @@ const MessageBox = ({
469416 onPaste = { handlePaste }
470417 aria-activedescendant = { popup . focused ? `popup-item-${ popup . focused . _id } ` : undefined }
471418 />
472- < MessageComposerFiles />
473- < MessageComposerToolbar >
474- < MessageComposerToolbarActions aria-label = { t ( 'Message_composer_toolbox_primary_actions' ) } >
475- < MessageComposerAction
476- icon = 'emoji'
477- disabled = { ! useEmojis || isRecording || ! canSend }
478- onClick = { handleOpenEmojiPicker }
479- title = { t ( 'Emoji' ) }
480- />
481- < MessageComposerActionsDivider />
482- { chat . composer && formatters . length > 0 && (
483- < MessageBoxFormattingToolbar
484- composer = { chat . composer }
485- variant = { sizes . inlineSize < 480 ? 'small' : 'large' }
486- items = { formatters }
487- disabled = { isRecording || ! canSend }
488- />
489- ) }
490- < MessageBoxActionsToolbar
491- canSend = { canSend }
492- isMicrophoneDenied = { isMicrophoneDenied }
493- rid = { room . _id }
494- tmid = { tmid }
495- isRecording = { isRecording }
496- variant = { sizes . inlineSize < 480 ? 'small' : 'large' }
497- isEditing = { isEditing }
498- />
499- </ MessageComposerToolbarActions >
500- < MessageComposerToolbarSubmit >
501- { ! canSend && (
502- < MessageComposerButton primary onClick = { onJoin } loading = { joinMutation . isPending } >
503- { t ( 'Join' ) }
504- </ MessageComposerButton >
505- ) }
506- { canSend && (
507- < >
508- { isEditing && < MessageComposerButton onClick = { closeEditing } > { t ( 'Cancel' ) } </ MessageComposerButton > }
509- < MessageComposerAction
510- aria-label = { t ( 'Send' ) }
511- icon = 'send'
512- disabled = { ! canSend || isUploading || isProcessingUploads || ( ! typing && ! isEditing && ! hasUploads ) }
513- onClick = { handleSendMessage }
514- secondary = { typing || isEditing || hasUploads }
515- info = { typing || isEditing || hasUploads }
516- />
517- </ >
518- ) }
519- </ MessageComposerToolbarSubmit >
520- </ MessageComposerToolbar >
521- </ MessageComposer >
522- < ComposerUserActionIndicator rid = { room . _id } tmid = { tmid } />
523- </ >
419+ }
420+ files = { < MessageComposerFiles /> }
421+ />
524422 ) ;
525423} ;
526424
0 commit comments