@@ -17,8 +17,7 @@ limitations under the License.
1717*/
1818
1919import React , { useEffect } from 'react' ;
20- import PropTypes from 'prop-types' ;
21- import { EventStatus } from 'matrix-js-sdk/src/models/event' ;
20+ import { MatrixEvent , EventStatus } from 'matrix-js-sdk/src/models/event' ;
2221
2322import { _t } from '../../../languageHandler' ;
2423import * as sdk from '../../../index' ;
@@ -37,48 +36,65 @@ import { MatrixClientPeg } from "../../../MatrixClientPeg";
3736import { MediaEventHelper } from "../../../utils/MediaEventHelper" ;
3837import DownloadActionButton from "./DownloadActionButton" ;
3938import SettingsStore from '../../../settings/SettingsStore' ;
39+ import { RoomPermalinkCreator } from '../../../utils/permalinks/Permalinks' ;
40+ import ReplyThread from '../elements/ReplyThread' ;
41+
42+ interface IOptionsButtonProps {
43+ mxEvent : MatrixEvent ;
44+ getTile : ( ) => any ; // TODO: FIXME, haven't figured out what the return type is here
45+ getReplyThread : ( ) => ReplyThread ;
46+ permalinkCreator : RoomPermalinkCreator ;
47+ onFocusChange : ( menuDisplayed : boolean ) => void ;
48+ }
4049
41- const OptionsButton = ( { mxEvent, getTile, getReplyThread, permalinkCreator, onFocusChange } ) => {
42- const [ menuDisplayed , button , openMenu , closeMenu ] = useContextMenu ( ) ;
43- const [ onFocus , isActive , ref ] = useRovingTabIndex ( button ) ;
44- useEffect ( ( ) => {
45- onFocusChange ( menuDisplayed ) ;
46- } , [ onFocusChange , menuDisplayed ] ) ;
47-
48- let contextMenu ;
49- if ( menuDisplayed ) {
50- const MessageContextMenu = sdk . getComponent ( 'context_menus.MessageContextMenu' ) ;
51-
52- const tile = getTile && getTile ( ) ;
53- const replyThread = getReplyThread && getReplyThread ( ) ;
54-
55- const buttonRect = button . current . getBoundingClientRect ( ) ;
56- contextMenu = < MessageContextMenu
57- { ...aboveLeftOf ( buttonRect ) }
58- mxEvent = { mxEvent }
59- permalinkCreator = { permalinkCreator }
60- eventTileOps = { tile && tile . getEventTileOps ? tile . getEventTileOps ( ) : undefined }
61- collapseReplyThread = { replyThread && replyThread . canCollapse ( ) ? replyThread . collapse : undefined }
62- onFinished = { closeMenu }
63- /> ;
64- }
50+ const OptionsButton : React . FC < IOptionsButtonProps > =
51+ ( { mxEvent, getTile, getReplyThread, permalinkCreator, onFocusChange } ) => {
52+ const [ menuDisplayed , button , openMenu , closeMenu ] = useContextMenu ( ) ;
53+ const [ onFocus , isActive , ref ] = useRovingTabIndex ( button ) ;
54+ useEffect ( ( ) => {
55+ onFocusChange ( menuDisplayed ) ;
56+ } , [ onFocusChange , menuDisplayed ] ) ;
57+
58+ let contextMenu ;
59+ if ( menuDisplayed ) {
60+ const MessageContextMenu = sdk . getComponent ( 'context_menus.MessageContextMenu' ) ;
61+
62+ const tile = getTile && getTile ( ) ;
63+ const replyThread = getReplyThread && getReplyThread ( ) ;
64+
65+ const buttonRect = button . current . getBoundingClientRect ( ) ;
66+ contextMenu = < MessageContextMenu
67+ { ...aboveLeftOf ( buttonRect ) }
68+ mxEvent = { mxEvent }
69+ permalinkCreator = { permalinkCreator }
70+ eventTileOps = { tile && tile . getEventTileOps ? tile . getEventTileOps ( ) : undefined }
71+ collapseReplyThread = { replyThread && replyThread . canCollapse ( ) ? replyThread . collapse : undefined }
72+ onFinished = { closeMenu }
73+ /> ;
74+ }
6575
66- return < React . Fragment >
67- < ContextMenuTooltipButton
68- className = "mx_MessageActionBar_maskButton mx_MessageActionBar_optionsButton"
69- title = { _t ( "Options" ) }
70- onClick = { openMenu }
71- isExpanded = { menuDisplayed }
72- inputRef = { ref }
73- onFocus = { onFocus }
74- tabIndex = { isActive ? 0 : - 1 }
75- />
76+ return < React . Fragment >
77+ < ContextMenuTooltipButton
78+ className = "mx_MessageActionBar_maskButton mx_MessageActionBar_optionsButton"
79+ title = { _t ( "Options" ) }
80+ onClick = { openMenu }
81+ isExpanded = { menuDisplayed }
82+ inputRef = { ref }
83+ onFocus = { onFocus }
84+ tabIndex = { isActive ? 0 : - 1 }
85+ />
86+
87+ { contextMenu }
88+ </ React . Fragment > ;
89+ } ;
7690
77- { contextMenu }
78- </ React . Fragment > ;
79- } ;
91+ interface IReactButtonProps {
92+ mxEvent : MatrixEvent ;
93+ reactions : any ; // TODO: types
94+ onFocusChange : ( menuDisplayed : boolean ) => void ;
95+ }
8096
81- const ReactButton = ( { mxEvent, reactions, onFocusChange } ) => {
97+ const ReactButton : React . FC < IReactButtonProps > = ( { mxEvent, reactions, onFocusChange } ) => {
8298 const [ menuDisplayed , button , openMenu , closeMenu ] = useContextMenu ( ) ;
8399 const [ onFocus , isActive , ref ] = useRovingTabIndex ( button ) ;
84100 useEffect ( ( ) => {
@@ -109,21 +125,21 @@ const ReactButton = ({ mxEvent, reactions, onFocusChange }) => {
109125 </ React . Fragment > ;
110126} ;
111127
112- @replaceableComponent ( "views.messages.MessageActionBar" )
113- export default class MessageActionBar extends React . PureComponent {
114- static propTypes = {
115- mxEvent : PropTypes . object . isRequired ,
116- // The Relations model from the JS SDK for reactions to `mxEvent`
117- reactions : PropTypes . object ,
118- permalinkCreator : PropTypes . object ,
119- getTile : PropTypes . func ,
120- getReplyThread : PropTypes . func ,
121- onFocusChange : PropTypes . func ,
122- } ;
128+ interface IMessageActionBarProps {
129+ mxEvent : MatrixEvent ;
130+ // The Relations model from the JS SDK for reactions to `mxEvent`
131+ reactions ?: any ; // TODO: types
132+ permalinkCreator ?: RoomPermalinkCreator ;
133+ getTile : ( ) => any ; // TODO: FIXME, haven't figured out what the return type is here
134+ getReplyThread ?: ( ) => ReplyThread ;
135+ onFocusChange ?: ( menuDisplayed : boolean ) => void ;
136+ }
123137
124- static contextType = RoomContext ;
138+ @replaceableComponent ( "views.messages.MessageActionBar" )
139+ export default class MessageActionBar extends React . PureComponent < IMessageActionBarProps > {
140+ public static contextType = RoomContext ;
125141
126- componentDidMount ( ) {
142+ public componentDidMount ( ) : void {
127143 if ( this . props . mxEvent . status && this . props . mxEvent . status !== EventStatus . SENT ) {
128144 this . props . mxEvent . on ( "Event.status" , this . onSent ) ;
129145 }
@@ -137,43 +153,43 @@ export default class MessageActionBar extends React.PureComponent {
137153 this . props . mxEvent . on ( "Event.beforeRedaction" , this . onBeforeRedaction ) ;
138154 }
139155
140- componentWillUnmount ( ) {
156+ public componentWillUnmount ( ) : void {
141157 this . props . mxEvent . off ( "Event.status" , this . onSent ) ;
142158 this . props . mxEvent . off ( "Event.decrypted" , this . onDecrypted ) ;
143159 this . props . mxEvent . off ( "Event.beforeRedaction" , this . onBeforeRedaction ) ;
144160 }
145161
146- onDecrypted = ( ) => {
162+ private onDecrypted = ( ) : void => {
147163 // When an event decrypts, it is likely to change the set of available
148164 // actions, so we force an update to check again.
149165 this . forceUpdate ( ) ;
150166 } ;
151167
152- onBeforeRedaction = ( ) => {
168+ private onBeforeRedaction = ( ) : void => {
153169 // When an event is redacted, we can't edit it so update the available actions.
154170 this . forceUpdate ( ) ;
155171 } ;
156172
157- onSent = ( ) => {
173+ private onSent = ( ) : void => {
158174 // When an event is sent and echoed the possible actions change.
159175 this . forceUpdate ( ) ;
160176 } ;
161177
162- onFocusChange = ( focused ) => {
178+ private onFocusChange = ( focused : boolean ) : void => {
163179 if ( ! this . props . onFocusChange ) {
164180 return ;
165181 }
166182 this . props . onFocusChange ( focused ) ;
167183 } ;
168184
169- onReplyClick = ( ev ) => {
185+ private onReplyClick = ( ev : React . MouseEvent ) : void => {
170186 dis . dispatch ( {
171187 action : 'reply_to_event' ,
172188 event : this . props . mxEvent ,
173189 } ) ;
174190 } ;
175191
176- onThreadClick = ( ) => {
192+ private onThreadClick = ( ) : void => {
177193 dis . dispatch ( {
178194 action : Action . SetRightPanelPhase ,
179195 phase : RightPanelPhases . ThreadView ,
@@ -182,9 +198,9 @@ export default class MessageActionBar extends React.PureComponent {
182198 event : this . props . mxEvent ,
183199 } ,
184200 } ) ;
185- }
201+ } ;
186202
187- onEditClick = ( ev ) => {
203+ private onEditClick = ( ev : React . MouseEvent ) : void => {
188204 dis . dispatch ( {
189205 action : 'edit_event' ,
190206 event : this . props . mxEvent ,
@@ -200,7 +216,7 @@ export default class MessageActionBar extends React.PureComponent {
200216 * @param {Function } fn The execution function.
201217 * @param {Function } checkFn The test function.
202218 */
203- runActionOnFailedEv ( fn , checkFn ) {
219+ private runActionOnFailedEv ( fn : ( ev : MatrixEvent ) => void , checkFn ?: ( ev : MatrixEvent ) => boolean ) : void {
204220 if ( ! checkFn ) checkFn = ( ) => true ;
205221
206222 const mxEvent = this . props . mxEvent ;
@@ -215,18 +231,18 @@ export default class MessageActionBar extends React.PureComponent {
215231 }
216232 }
217233
218- onResendClick = ( ev ) => {
234+ private onResendClick = ( ev : React . MouseEvent ) : void => {
219235 this . runActionOnFailedEv ( ( tarEv ) => Resend . resend ( tarEv ) ) ;
220236 } ;
221237
222- onCancelClick = ( ev ) => {
238+ private onCancelClick = ( ev : React . MouseEvent ) : void => {
223239 this . runActionOnFailedEv (
224240 ( tarEv ) => Resend . removeFromQueue ( tarEv ) ,
225241 ( testEv ) => canCancel ( testEv . status ) ,
226242 ) ;
227243 } ;
228244
229- render ( ) {
245+ public render ( ) : JSX . Element {
230246 const toolbarOpts = [ ] ;
231247 if ( canEditContent ( this . props . mxEvent ) ) {
232248 toolbarOpts . push ( < RovingAccessibleTooltipButton
@@ -249,7 +265,7 @@ export default class MessageActionBar extends React.PureComponent {
249265 const editStatus = mxEvent . replacingEvent ( ) && mxEvent . replacingEvent ( ) . status ;
250266 const redactStatus = mxEvent . localRedactionEvent ( ) && mxEvent . localRedactionEvent ( ) . status ;
251267 const allowCancel = canCancel ( mxEvent . status ) || canCancel ( editStatus ) || canCancel ( redactStatus ) ;
252- const isFailed = [ mxEvent . status , editStatus , redactStatus ] . includes ( "not_sent" ) ;
268+ const isFailed = [ mxEvent . status , editStatus , redactStatus ] . includes ( EventStatus . NOT_SENT ) ;
253269 if ( allowCancel && isFailed ) {
254270 // The resend button needs to appear ahead of the edit button, so insert to the
255271 // start of the opts
0 commit comments