11/*
2- Copyright 2019 New Vector Ltd
2+ Copyright 2019, 2021 The Matrix.org Foundation C.I.C.
33
44Licensed under the Apache License, Version 2.0 (the "License");
55you may not use this file except in compliance with the License.
@@ -14,29 +14,68 @@ See the License for the specific language governing permissions and
1414limitations under the License.
1515*/
1616
17- import React from 'react' ;
18- import PropTypes from 'prop-types' ;
17+ import React from "react" ;
18+ import classNames from "classnames" ;
19+ import { EventType } from "matrix-js-sdk/src/@types/event" ;
20+ import { MatrixEvent } from "matrix-js-sdk/src/models/event" ;
21+ import { Relations } from "matrix-js-sdk/src/models/relations" ;
1922
20- import * as sdk from '../../../index' ;
2123import { _t } from '../../../languageHandler' ;
2224import { isContentActionable } from '../../../utils/EventUtils' ;
23- import { MatrixClientPeg } from '../../../MatrixClientPeg' ;
24- import { replaceableComponent } from "../../../utils/replaceableComponent" ;
25+ import { replaceableComponent } from "../../../utils/replaceableComponent" ;
26+ import { ContextMenuTooltipButton } from "../../../accessibility/context_menu/ContextMenuTooltipButton" ;
27+ import { aboveLeftOf , ContextMenu , useContextMenu } from "../../structures/ContextMenu" ;
28+ import ReactionPicker from "../emojipicker/ReactionPicker" ;
29+ import ReactionsRowButton from "./ReactionsRowButton" ;
30+ import MatrixClientContext from "../../../contexts/MatrixClientContext" ;
2531
2632// The maximum number of reactions to initially show on a message.
2733const MAX_ITEMS_WHEN_LIMITED = 8 ;
2834
29- @replaceableComponent ( "views.messages.ReactionsRow" )
30- export default class ReactionsRow extends React . PureComponent {
31- static propTypes = {
32- // The event we're displaying reactions for
33- mxEvent : PropTypes . object . isRequired ,
34- // The Relations model from the JS SDK for reactions to `mxEvent`
35- reactions : PropTypes . object ,
35+ const ReactButton = ( { mxEvent, reactions } : IProps ) => {
36+ const [ menuDisplayed , button , openMenu , closeMenu ] = useContextMenu ( ) ;
37+
38+ let contextMenu ;
39+ if ( menuDisplayed ) {
40+ const buttonRect = button . current . getBoundingClientRect ( ) ;
41+ contextMenu = < ContextMenu { ...aboveLeftOf ( buttonRect ) } onFinished = { closeMenu } managed = { false } >
42+ < ReactionPicker mxEvent = { mxEvent } reactions = { reactions } onFinished = { closeMenu } />
43+ </ ContextMenu > ;
3644 }
3745
38- constructor ( props ) {
39- super ( props ) ;
46+ return < React . Fragment >
47+ < ContextMenuTooltipButton
48+ className = { classNames ( "mx_ReactionsRow_addReactionButton" , {
49+ mx_ReactionsRow_addReactionButton_active : menuDisplayed ,
50+ } ) }
51+ title = { _t ( "Add reaction" ) }
52+ onClick = { openMenu }
53+ isExpanded = { menuDisplayed }
54+ inputRef = { button }
55+ />
56+
57+ { contextMenu }
58+ </ React . Fragment > ;
59+ } ;
60+
61+ interface IProps {
62+ // The event we're displaying reactions for
63+ mxEvent : MatrixEvent ;
64+ // The Relations model from the JS SDK for reactions to `mxEvent`
65+ reactions ?: Relations ;
66+ }
67+
68+ interface IState {
69+ myReactions : MatrixEvent [ ] ;
70+ showAll : boolean ;
71+ }
72+
73+ @replaceableComponent ( "views.messages.ReactionsRow" )
74+ export default class ReactionsRow extends React . PureComponent < IProps , IState > {
75+ static contextType = MatrixClientContext ;
76+
77+ constructor ( props , context ) {
78+ super ( props , context ) ;
4079
4180 if ( props . reactions ) {
4281 props . reactions . on ( "Relations.add" , this . onReactionsChange ) ;
@@ -92,7 +131,7 @@ export default class ReactionsRow extends React.PureComponent {
92131 if ( ! reactions ) {
93132 return null ;
94133 }
95- const userId = MatrixClientPeg . get ( ) . getUserId ( ) ;
134+ const userId = this . context . getUserId ( ) ;
96135 const myReactions = reactions . getAnnotationsBySender ( ) [ userId ] ;
97136 if ( ! myReactions ) {
98137 return null ;
@@ -114,7 +153,6 @@ export default class ReactionsRow extends React.PureComponent {
114153 return null ;
115154 }
116155
117- const ReactionsRowButton = sdk . getComponent ( 'messages.ReactionsRowButton' ) ;
118156 let items = reactions . getSortedAnnotationsByKey ( ) . map ( ( [ content , events ] ) => {
119157 const count = events . size ;
120158 if ( ! count ) {
@@ -151,13 +189,21 @@ export default class ReactionsRow extends React.PureComponent {
151189 </ a > ;
152190 }
153191
192+ const cli = this . context ;
193+
194+ let addReactionButton ;
195+ if ( cli . getRoom ( mxEvent . getRoomId ( ) ) . currentState . maySendEvent ( EventType . Reaction , cli . getUserId ( ) ) ) {
196+ addReactionButton = < ReactButton mxEvent = { mxEvent } reactions = { reactions } /> ;
197+ }
198+
154199 return < div
155200 className = "mx_ReactionsRow"
156201 role = "toolbar"
157202 aria-label = { _t ( "Reactions" ) }
158203 >
159- { items }
160- { showAllButton }
204+ { items }
205+ { showAllButton }
206+ { addReactionButton }
161207 </ div > ;
162208 }
163209}
0 commit comments