@@ -13,7 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313See the License for the specific language governing permissions and
1414limitations under the License.
1515*/
16- import React , { createRef } from 'react' ;
16+ import React from 'react' ;
1717import classNames from 'classnames' ;
1818import { _t } from '../../../languageHandler' ;
1919import { MatrixClientPeg } from '../../../MatrixClientPeg' ;
@@ -27,13 +27,7 @@ import { makeRoomPermalink, RoomPermalinkCreator } from '../../../utils/permalin
2727import ContentMessages from '../../../ContentMessages' ;
2828import E2EIcon from './E2EIcon' ;
2929import SettingsStore from "../../../settings/SettingsStore" ;
30- import {
31- aboveLeftOf ,
32- ContextMenu ,
33- ContextMenuTooltipButton ,
34- useContextMenu ,
35- MenuItem ,
36- } from "../../structures/ContextMenu" ;
30+ import { aboveLeftOf , ContextMenu , ContextMenuTooltipButton , useContextMenu } from "../../structures/ContextMenu" ;
3731import AccessibleTooltipButton from "../elements/AccessibleTooltipButton" ;
3832import ReplyPreview from "./ReplyPreview" ;
3933import { UIFeature } from "../../../settings/UIFeature" ;
@@ -51,9 +45,6 @@ import { Action } from "../../../dispatcher/actions";
5145import EditorModel from "../../../editor/model" ;
5246import EmojiPicker from '../emojipicker/EmojiPicker' ;
5347import MemberStatusMessageAvatar from "../avatars/MemberStatusMessageAvatar" ;
54- import UIStore , { UI_EVENTS } from '../../../stores/UIStore' ;
55-
56- const NARROW_MODE_BREAKPOINT = 500 ;
5748
5849interface IComposerAvatarProps {
5950 me : object ;
@@ -80,13 +71,13 @@ function SendButton(props: ISendButtonProps) {
8071 ) ;
8172}
8273
83- const EmojiButton = ( { addEmoji, menuPosition } ) => {
74+ const EmojiButton = ( { addEmoji } ) => {
8475 const [ menuDisplayed , button , openMenu , closeMenu ] = useContextMenu ( ) ;
8576
8677 let contextMenu ;
8778 if ( menuDisplayed ) {
88- const position = menuPosition ?? aboveLeftOf ( button . current . getBoundingClientRect ( ) ) ;
89- contextMenu = < ContextMenu { ...position } onFinished = { closeMenu } managed = { false } >
79+ const buttonRect = button . current . getBoundingClientRect ( ) ;
80+ contextMenu = < ContextMenu { ...aboveLeftOf ( buttonRect ) } onFinished = { closeMenu } managed = { false } >
9081 < EmojiPicker onChoose = { addEmoji } showQuickReactions = { true } />
9182 </ ContextMenu > ;
9283 }
@@ -205,17 +196,13 @@ interface IState {
205196 haveRecording : boolean ;
206197 recordingTimeLeftSeconds ?: number ;
207198 me ?: RoomMember ;
208- narrowMode ?: boolean ;
209- isMenuOpen : boolean ;
210- showStickers : boolean ;
211199}
212200
213201@replaceableComponent ( "views.rooms.MessageComposer" )
214202export default class MessageComposer extends React . Component < IProps , IState > {
215203 private dispatcherRef : string ;
216204 private messageComposerInput : SendMessageComposer ;
217205 private voiceRecordingButton : VoiceRecordComposerTile ;
218- private ref : React . RefObject < HTMLDivElement > = createRef ( ) ;
219206
220207 static defaultProps = {
221208 replyInThread : false ,
@@ -233,30 +220,15 @@ export default class MessageComposer extends React.Component<IProps, IState> {
233220 isComposerEmpty : true ,
234221 haveRecording : false ,
235222 recordingTimeLeftSeconds : null , // when set to a number, shows a toast
236- isMenuOpen : false ,
237- showStickers : false ,
238223 } ;
239224 }
240225
241226 componentDidMount ( ) {
242227 this . dispatcherRef = dis . register ( this . onAction ) ;
243228 MatrixClientPeg . get ( ) . on ( "RoomState.events" , this . onRoomStateEvents ) ;
244229 this . waitForOwnMember ( ) ;
245- UIStore . instance . trackElementDimensions ( "MessageComposer" , this . ref . current ) ;
246- UIStore . instance . on ( "MessageComposer" , this . onResize ) ;
247230 }
248231
249- private onResize = ( type : UI_EVENTS , entry : ResizeObserverEntry ) => {
250- if ( type === UI_EVENTS . Resize ) {
251- const narrowMode = entry . contentRect . width <= NARROW_MODE_BREAKPOINT ;
252- this . setState ( {
253- narrowMode,
254- isMenuOpen : ! narrowMode ? false : this . state . isMenuOpen ,
255- showStickers : false ,
256- } ) ;
257- }
258- } ;
259-
260232 private onAction = ( payload : ActionPayload ) => {
261233 if ( payload . action === 'reply_to_event' ) {
262234 // add a timeout for the reply preview to be rendered, so
@@ -291,8 +263,6 @@ export default class MessageComposer extends React.Component<IProps, IState> {
291263 }
292264 VoiceRecordingStore . instance . off ( UPDATE_EVENT , this . onVoiceStoreUpdate ) ;
293265 dis . unregister ( this . dispatcherRef ) ;
294- UIStore . instance . stopTrackingElementDimensions ( "MessageComposer" ) ;
295- UIStore . instance . removeListener ( "MessageComposer" , this . onResize ) ;
296266 }
297267
298268 private onRoomStateEvents = ( ev , state ) => {
@@ -399,96 +369,6 @@ export default class MessageComposer extends React.Component<IProps, IState> {
399369 }
400370 } ;
401371
402- private shouldShowStickerPicker = ( ) : boolean => {
403- return SettingsStore . getValue ( UIFeature . Widgets )
404- && SettingsStore . getValue ( "MessageComposerInput.showStickersButton" )
405- && ! this . state . haveRecording ;
406- } ;
407-
408- private showStickers = ( showStickers : boolean ) => {
409- this . setState ( { showStickers } ) ;
410- } ;
411-
412- private toggleButtonMenu = ( ) : void => {
413- this . setState ( {
414- isMenuOpen : ! this . state . isMenuOpen ,
415- } ) ;
416- } ;
417-
418- private renderButtons ( menuPosition ) : JSX . Element | JSX . Element [ ] {
419- const buttons = new Map < string , JSX . Element > ( ) ;
420- if ( ! this . state . haveRecording ) {
421- buttons . set (
422- _t ( "Send File" ) ,
423- < UploadButton key = "controls_upload" roomId = { this . props . room . roomId } /> ,
424- ) ;
425- buttons . set (
426- _t ( "Show Emojis" ) ,
427- < EmojiButton key = "emoji_button" addEmoji = { this . addEmoji } menuPosition = { menuPosition } /> ,
428- ) ;
429- }
430- if ( this . shouldShowStickerPicker ( ) ) {
431- buttons . set (
432- _t ( "Show Stickers" ) ,
433- < AccessibleTooltipButton
434- id = 'stickersButton'
435- key = "controls_stickers"
436- className = "mx_MessageComposer_button mx_MessageComposer_stickers"
437- onClick = { ( ) => this . showStickers ( ! this . state . showStickers ) }
438- title = { this . state . showStickers ? _t ( "Hide Stickers" ) : _t ( "Show Stickers" ) }
439- /> ,
440- ) ;
441- }
442- if ( ! this . state . haveRecording && ! this . state . narrowMode ) {
443- buttons . set (
444- _t ( "Send voice message" ) ,
445- < AccessibleTooltipButton
446- className = "mx_MessageComposer_button mx_MessageComposer_voiceMessage"
447- onClick = { ( ) => this . voiceRecordingButton ?. onRecordStartEndClick ( ) }
448- title = { _t ( "Send voice message" ) }
449- /> ,
450- ) ;
451- }
452-
453- if ( ! this . state . narrowMode ) {
454- return Array . from ( buttons . values ( ) ) ;
455- } else {
456- const classnames = classNames ( {
457- mx_MessageComposer_button : true ,
458- mx_MessageComposer_buttonMenu : true ,
459- mx_MessageComposer_closeButtonMenu : this . state . isMenuOpen ,
460- } ) ;
461-
462- return < >
463- { buttons [ 0 ] }
464- < AccessibleTooltipButton
465- className = { classnames }
466- onClick = { this . toggleButtonMenu }
467- title = { _t ( "Composer menu" ) }
468- tooltip = { false }
469- />
470- { this . state . isMenuOpen && (
471- < ContextMenu
472- onFinished = { this . toggleButtonMenu }
473- { ...menuPosition }
474- menuPaddingRight = { 10 }
475- menuPaddingTop = { 5 }
476- menuPaddingBottom = { 5 }
477- menuWidth = { 150 }
478- wrapperClassName = "mx_MessageComposer_Menu"
479- >
480- { Array . from ( buttons ) . slice ( 1 ) . map ( ( [ label , button ] ) => (
481- < MenuItem className = "mx_CallContextMenu_item" key = { label } onClick = { this . toggleButtonMenu } >
482- { button }
483- { label }
484- </ MenuItem >
485- ) ) }
486- </ ContextMenu >
487- ) }
488- </ > ;
489- }
490- }
491-
492372 render ( ) {
493373 const controls = [
494374 this . state . me && ! this . props . compact ? < ComposerAvatar key = "controls_avatar" me = { this . state . me } /> : null ,
@@ -497,12 +377,6 @@ export default class MessageComposer extends React.Component<IProps, IState> {
497377 null ,
498378 ] ;
499379
500- let menuPosition ;
501- if ( this . ref . current ) {
502- const contentRect = this . ref . current . getBoundingClientRect ( ) ;
503- menuPosition = aboveLeftOf ( contentRect ) ;
504- }
505-
506380 if ( ! this . state . tombstone && this . state . canSendMessages ) {
507381 controls . push (
508382 < SendMessageComposer
@@ -518,10 +392,33 @@ export default class MessageComposer extends React.Component<IProps, IState> {
518392 /> ,
519393 ) ;
520394
395+ if ( ! this . state . haveRecording ) {
396+ controls . push (
397+ < UploadButton key = "controls_upload" roomId = { this . props . room . roomId } /> ,
398+ < EmojiButton key = "emoji_button" addEmoji = { this . addEmoji } /> ,
399+ ) ;
400+ }
401+
402+ if ( SettingsStore . getValue ( UIFeature . Widgets ) &&
403+ SettingsStore . getValue ( "MessageComposerInput.showStickersButton" ) &&
404+ ! this . state . haveRecording ) {
405+ controls . push ( < Stickerpicker key = "stickerpicker_controls_button" room = { this . props . room } /> ) ;
406+ }
407+
521408 controls . push ( < VoiceRecordComposerTile
522409 key = "controls_voice_record"
523410 ref = { c => this . voiceRecordingButton = c }
524411 room = { this . props . room } /> ) ;
412+
413+ if ( ! this . state . isComposerEmpty || this . state . haveRecording ) {
414+ controls . push (
415+ < SendButton
416+ key = "controls_send"
417+ onClick = { this . sendMessage }
418+ title = { this . state . haveRecording ? _t ( "Send voice message" ) : undefined }
419+ /> ,
420+ ) ;
421+ }
525422 } else if ( this . state . tombstone ) {
526423 const replacementRoomId = this . state . tombstone . getContent ( ) [ 'replacement_room' ] ;
527424
@@ -562,15 +459,6 @@ export default class MessageComposer extends React.Component<IProps, IState> {
562459 yOffset = { - 50 }
563460 /> ;
564461 }
565- controls . push (
566- < Stickerpicker
567- room = { this . props . room }
568- showStickers = { this . state . showStickers }
569- setShowStickers = { this . showStickers }
570- menuPosition = { menuPosition } /> ,
571- ) ;
572-
573- const showSendButton = ! this . state . isComposerEmpty || this . state . haveRecording ;
574462
575463 const classes = classNames ( {
576464 "mx_MessageComposer" : true ,
@@ -579,22 +467,14 @@ export default class MessageComposer extends React.Component<IProps, IState> {
579467 } ) ;
580468
581469 return (
582- < div className = { classes } ref = { this . ref } >
470+ < div className = { classes } >
583471 { recordingTooltip }
584472 < div className = "mx_MessageComposer_wrapper" >
585473 { this . props . showReplyPreview && (
586474 < ReplyPreview permalinkCreator = { this . props . permalinkCreator } />
587475 ) }
588476 < div className = "mx_MessageComposer_row" >
589477 { controls }
590- { this . renderButtons ( menuPosition ) }
591- { showSendButton && (
592- < SendButton
593- key = "controls_send"
594- onClick = { this . sendMessage }
595- title = { this . state . haveRecording ? _t ( "Send voice message" ) : undefined }
596- />
597- ) }
598478 </ div >
599479 </ div >
600480 </ div >
0 commit comments