From 26f732723ebbfc749dc0cc08ecde243a730df58e Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Thu, 25 Apr 2019 11:10:35 +0100 Subject: [PATCH] Animate tooltips when hiding as well as showing This uses the same animation style as on show, but twice as fast. --- res/css/views/elements/_Tooltip.scss | 9 ++++++++- src/components/views/elements/Field.js | 22 ++++++++++++++++++---- src/components/views/elements/Tooltip.js | 15 ++++++++++++++- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/res/css/views/elements/_Tooltip.scss b/res/css/views/elements/_Tooltip.scss index 2f35bd338e..43ddf6dde5 100644 --- a/res/css/views/elements/_Tooltip.scss +++ b/res/css/views/elements/_Tooltip.scss @@ -50,7 +50,6 @@ limitations under the License. .mx_Tooltip { display: none; - animation: mx_fadein 0.2s; position: fixed; border: 1px solid $menu-border-color; border-radius: 4px; @@ -66,4 +65,12 @@ limitations under the License. max-width: 200px; word-break: break-word; margin-right: 50px; + + &.mx_Tooltip_visible { + animation: mx_fadein 0.2s forwards; + } + + &.mx_Tooltip_invisible { + animation: mx_fadeout 0.1s forwards; + } } diff --git a/src/components/views/elements/Field.js b/src/components/views/elements/Field.js index 91447a8846..93bea70fc8 100644 --- a/src/components/views/elements/Field.js +++ b/src/components/views/elements/Field.js @@ -99,10 +99,23 @@ export default class Field extends React.PureComponent { focused, allowEmpty, }); - this.setState({ - valid, - feedback, - }); + + if (feedback) { + this.setState({ + valid, + feedback, + feedbackVisible: true, + }); + } else { + // When we receive null `feedback`, we want to hide the tooltip. + // We leave the previous `feedback` content in state without updating it, + // so that we can hide the tooltip containing the most recent feedback + // via CSS animation. + this.setState({ + valid, + feedbackVisible: false, + }); + } } validateOnChange = throttle(() => { @@ -147,6 +160,7 @@ export default class Field extends React.PureComponent { if (this.state.feedback) { tooltip = ; } diff --git a/src/components/views/elements/Tooltip.js b/src/components/views/elements/Tooltip.js index 473aeb3bdc..1cc82978ed 100644 --- a/src/components/views/elements/Tooltip.js +++ b/src/components/views/elements/Tooltip.js @@ -31,10 +31,20 @@ module.exports = React.createClass({ className: React.PropTypes.string, // Class applied to the tooltip itself tooltipClassName: React.PropTypes.string, + // Whether the tooltip is visible or hidden. + // The hidden state allows animating the tooltip away via CSS. + // Defaults to visible if unset. + visible: React.PropTypes.bool, // the react element to put into the tooltip label: React.PropTypes.node, }, + getDefaultProps() { + return { + visible: true, + }; + }, + // Create a wrapper for the tooltip outside the parent and attach it to the body element componentDidMount: function() { this.tooltipContainer = document.createElement("div"); @@ -85,7 +95,10 @@ module.exports = React.createClass({ style = this._updatePosition(style); style.display = "block"; - const tooltipClasses = classNames("mx_Tooltip", this.props.tooltipClassName); + const tooltipClasses = classNames("mx_Tooltip", this.props.tooltipClassName, { + "mx_Tooltip_visible": this.props.visible, + "mx_Tooltip_invisible": !this.props.visible, + }); const tooltip = (