diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx
index 4a4ac9e56c..15fc2e075e 100644
--- a/src/HtmlUtils.tsx
+++ b/src/HtmlUtils.tsx
@@ -632,13 +632,13 @@ export function topicToHtml(
emojiBodyElements = formatEmojis(topic, false);
}
- return isFormattedTopic ?
- :
+ />
+ :
{ emojiBodyElements || topic }
;
}
diff --git a/src/components/views/elements/Tooltip.tsx b/src/components/views/elements/Tooltip.tsx
index 3b7e6c9670..ae1aff26de 100644
--- a/src/components/views/elements/Tooltip.tsx
+++ b/src/components/views/elements/Tooltip.tsx
@@ -52,8 +52,10 @@ export interface ITooltipProps {
maxParentWidth?: number;
}
-export default class Tooltip extends React.Component {
- private tooltipContainer: HTMLElement;
+type State = Partial>;
+
+export default class Tooltip extends React.PureComponent {
+ private static container: HTMLElement;
private parent: Element;
// XXX: This is because some components (Field) are unable to `import` the Tooltip class,
@@ -65,37 +67,47 @@ export default class Tooltip extends React.Component {
alignment: Alignment.Natural,
};
- // Create a wrapper for the tooltip outside the parent and attach it to the body element
+ constructor(props) {
+ super(props);
+
+ this.state = {};
+
+ // Create a wrapper for the tooltips and attach it to the body element
+ if (!Tooltip.container) {
+ Tooltip.container = document.createElement("div");
+ Tooltip.container.className = "mx_Tooltip_wrapper";
+ document.body.appendChild(Tooltip.container);
+ }
+ }
+
public componentDidMount() {
- this.tooltipContainer = document.createElement("div");
- this.tooltipContainer.className = "mx_Tooltip_wrapper";
- document.body.appendChild(this.tooltipContainer);
- window.addEventListener('scroll', this.renderTooltip, {
+ window.addEventListener('scroll', this.updatePosition, {
passive: true,
capture: true,
});
this.parent = ReactDOM.findDOMNode(this).parentNode as Element;
- this.renderTooltip();
+ this.updatePosition();
}
public componentDidUpdate() {
- this.renderTooltip();
+ this.updatePosition();
}
// Remove the wrapper element, as the tooltip has finished using it
public componentWillUnmount() {
- ReactDOM.unmountComponentAtNode(this.tooltipContainer);
- document.body.removeChild(this.tooltipContainer);
- window.removeEventListener('scroll', this.renderTooltip, {
+ window.removeEventListener('scroll', this.updatePosition, {
capture: true,
});
}
// Add the parent's position to the tooltips, so it's correctly
// positioned, also taking into account any window zoom
- private updatePosition(style: CSSProperties) {
+ private updatePosition = (): void => {
+ // When the tooltip is hidden, no need to thrash the DOM with `style` attribute updates (performance)
+ if (!this.props.visible) return;
+
const parentBox = this.parent.getBoundingClientRect();
const width = UIStore.instance.windowWidth;
const spacing = 6;
@@ -112,6 +124,7 @@ export default class Tooltip extends React.Component {
parentBox.left - window.scrollX + (parentWidth / 2)
);
+ const style: State = {};
switch (this.props.alignment) {
case Alignment.Natural:
if (parentBox.right > width / 2) {
@@ -153,25 +166,20 @@ export default class Tooltip extends React.Component {
break;
}
- return style;
- }
-
- private renderTooltip = () => {
- let style: CSSProperties = {};
- // When the tooltip is hidden, no need to thrash the DOM with `style`
- // attribute updates (performance)
- if (this.props.visible) {
- style = this.updatePosition({});
- }
- // Hide the entire container when not visible. This prevents flashing of the tooltip
- // if it is not meant to be visible on first mount.
- style.display = this.props.visible ? "block" : "none";
+ this.setState(style);
+ };
+ public render() {
const tooltipClasses = classNames("mx_Tooltip", this.props.tooltipClassName, {
"mx_Tooltip_visible": this.props.visible,
"mx_Tooltip_invisible": !this.props.visible,
});
+ const style = { ...this.state };
+ // Hide the entire container when not visible.
+ // This prevents flashing of the tooltip if it is not meant to be visible on first mount.
+ style.display = this.props.visible ? "block" : "none";
+
const tooltip = (
);
- // Render the tooltip manually, as we wish it not to be rendered within the parent
- ReactDOM.render(tooltip, this.tooltipContainer);
- };
-
- public render() {
- // Render a placeholder
return (
-
+