diff --git a/res/css/views/elements/_Tooltip.scss b/res/css/views/elements/_Tooltip.scss index efaaf83545..7efea2c3f7 100644 --- a/res/css/views/elements/_Tooltip.scss +++ b/res/css/views/elements/_Tooltip.scss @@ -76,9 +76,6 @@ limitations under the License. } .mx_Tooltip_timeline { - margin-left: -42px; - margin-top: -42px; - &.mx_Tooltip { background-color: $inverted-bg-color; color: $accent-fg-color; diff --git a/src/components/views/elements/AccessibleTooltipButton.tsx b/src/components/views/elements/AccessibleTooltipButton.tsx index 45e769e32d..f4d63136e1 100644 --- a/src/components/views/elements/AccessibleTooltipButton.tsx +++ b/src/components/views/elements/AccessibleTooltipButton.tsx @@ -24,7 +24,6 @@ import Tooltip from './Tooltip'; interface ITooltipProps extends IProps { title: string; - tooltip?: React.ReactNode; tooltipClassName?: string; } @@ -53,7 +52,7 @@ export default class AccessibleTooltipButton extends React.PureComponent :
; return ( diff --git a/src/components/views/messages/ReactionsRowButton.js b/src/components/views/messages/ReactionsRowButton.js index 8c0cf3b0b0..09824cd315 100644 --- a/src/components/views/messages/ReactionsRowButton.js +++ b/src/components/views/messages/ReactionsRowButton.js @@ -19,11 +19,10 @@ import PropTypes from 'prop-types'; import classNames from 'classnames'; import {MatrixClientPeg} from '../../../MatrixClientPeg'; +import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import { formatCommaSeparatedList } from '../../../utils/FormattingUtils'; import dis from "../../../dispatcher/dispatcher"; -import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; -import {unicodeToShortcode} from "../../../HtmlUtils"; export default class ReactionsRowButton extends React.PureComponent { static propTypes = { @@ -39,6 +38,14 @@ export default class ReactionsRowButton extends React.PureComponent { myReactionEvent: PropTypes.object, } + constructor(props) { + super(props); + + this.state = { + tooltipVisible: false, + }; + } + onClick = (ev) => { const { mxEvent, myReactionEvent, content } = this.props; if (myReactionEvent) { @@ -58,7 +65,24 @@ export default class ReactionsRowButton extends React.PureComponent { } }; + onMouseOver = () => { + this.setState({ + // To avoid littering the DOM with a tooltip for every reaction, + // only render it on first use. + tooltipRendered: true, + tooltipVisible: true, + }); + } + + onMouseOut = () => { + this.setState({ + tooltipVisible: false, + }); + } + render() { + const ReactionsRowButtonTooltip = + sdk.getComponent('messages.ReactionsRowButtonTooltip'); const { mxEvent, content, count, reactionEvents, myReactionEvent } = this.props; const classes = classNames({ @@ -66,9 +90,18 @@ export default class ReactionsRowButton extends React.PureComponent { mx_ReactionsRowButton_selected: !!myReactionEvent, }); + let tooltip; + if (this.state.tooltipRendered) { + tooltip = ; + } + const room = MatrixClientPeg.get().getRoom(mxEvent.getRoomId()); let label; - let tooltip; if (room) { const senders = []; for (const reactionEvent of reactionEvents) { @@ -93,37 +126,14 @@ export default class ReactionsRowButton extends React.PureComponent { }, }, ); - - const shortName = unicodeToShortcode(content); - tooltip =
{_t( - "reacted with %(shortName)s", - { - shortName, - }, - { - reactors: () => { - return
- {formatCommaSeparatedList(senders, 6)} -
; - }, - reactedWith: (sub) => { - if (!shortName) { - return null; - } - return
- {sub} -
; - }, - }, - )}
; } - return ; + {tooltip} +
; } } diff --git a/src/components/views/messages/ReactionsRowButtonTooltip.js b/src/components/views/messages/ReactionsRowButtonTooltip.js new file mode 100644 index 0000000000..59e9d2ad7f --- /dev/null +++ b/src/components/views/messages/ReactionsRowButtonTooltip.js @@ -0,0 +1,85 @@ +/* +Copyright 2019 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from 'react'; +import PropTypes from 'prop-types'; + +import {MatrixClientPeg} from '../../../MatrixClientPeg'; +import * as sdk from '../../../index'; +import { unicodeToShortcode } from '../../../HtmlUtils'; +import { _t } from '../../../languageHandler'; +import { formatCommaSeparatedList } from '../../../utils/FormattingUtils'; + +export default class ReactionsRowButtonTooltip extends React.PureComponent { + static propTypes = { + // The event we're displaying reactions for + mxEvent: PropTypes.object.isRequired, + // The reaction content / key / emoji + content: PropTypes.string.isRequired, + // A Set of Martix reaction events for this key + reactionEvents: PropTypes.object.isRequired, + visible: PropTypes.bool.isRequired, + } + + render() { + const Tooltip = sdk.getComponent('elements.Tooltip'); + const { content, reactionEvents, mxEvent, visible } = this.props; + + const room = MatrixClientPeg.get().getRoom(mxEvent.getRoomId()); + let tooltipLabel; + if (room) { + const senders = []; + for (const reactionEvent of reactionEvents) { + const member = room.getMember(reactionEvent.getSender()); + const name = member ? member.name : reactionEvent.getSender(); + senders.push(name); + } + const shortName = unicodeToShortcode(content); + tooltipLabel =
{_t( + "reacted with %(shortName)s", + { + shortName, + }, + { + reactors: () => { + return
+ {formatCommaSeparatedList(senders, 6)} +
; + }, + reactedWith: (sub) => { + if (!shortName) { + return null; + } + return
+ {sub} +
; + }, + }, + )}
; + } + + let tooltip; + if (tooltipLabel) { + tooltip = ; + } + + return tooltip; + } +}