Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

7486 reduce tooltip over group #8494

Merged
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
6caff3c
convert to class, get ref, add styles
LucioChavezFuentes Mar 21, 2022
2674c63
finish proposal
LucioChavezFuentes Mar 22, 2022
aeb366d
move getCorrectWidth func
LucioChavezFuentes Mar 23, 2022
3c506fa
create tooltipHorizontalPadding, add new param
LucioChavezFuentes Mar 23, 2022
c3aa571
remove unneeded maximumWords prop
LucioChavezFuentes Mar 30, 2022
9e8271c
simplify code
LucioChavezFuentes Mar 31, 2022
5163c67
remove unneeded maximumWords prop
LucioChavezFuentes Mar 31, 2022
66c912e
insert maxWidth and numberLines props, move measureTooltip
LucioChavezFuentes Apr 4, 2022
3232093
Merge branch 'main' into 7486_reduce-tooltip-over-group
LucioChavezFuentes Apr 4, 2022
c8efb52
remove maxWidth numberOfLines default values
LucioChavezFuentes Apr 5, 2022
2c68ac7
fix minor capital letter comments
LucioChavezFuentes Apr 6, 2022
7b42881
set tooltipTextWidth and maxWidth as optional
LucioChavezFuentes Apr 6, 2022
6e0bfe6
remove displayName
LucioChavezFuentes Apr 6, 2022
25e2938
avoid set state on tooltips with no maxWidth
LucioChavezFuentes Apr 8, 2022
764c569
remove memo, make component Pure, minor changes
LucioChavezFuentes Apr 8, 2022
c2e46ad
tooltip settings, create setWrapperWidth
LucioChavezFuentes Apr 8, 2022
259f44e
fix comment about adding 1px, add consts, minor changes
LucioChavezFuentes Apr 11, 2022
24bcfab
move TOOLTIP_MAX_LINES to CONST
LucioChavezFuentes Apr 12, 2022
39e859b
change comment about 1px add, minor change
LucioChavezFuentes Apr 12, 2022
f0524e7
set default values numberOfLines maxWidth, remove check
LucioChavezFuentes Apr 15, 2022
9229a4c
remove unneccesary props
LucioChavezFuentes Apr 15, 2022
0042574
return maxWidth if tooltipTextWidth is not set
LucioChavezFuentes Apr 15, 2022
707a4ff
minor comment change
LucioChavezFuentes Apr 15, 2022
f6a2832
avoid re-render on single line tooltips, minor changes
LucioChavezFuentes Apr 20, 2022
7b6abee
use width instead of max-width
LucioChavezFuentes Apr 25, 2022
3b6048e
remove check on componentDidMount
LucioChavezFuentes Apr 25, 2022
b66427b
remove unneccesary function, simplify code
LucioChavezFuentes Apr 25, 2022
706f227
move wrapper width logic close to its variables
LucioChavezFuentes Apr 26, 2022
b64b96e
Merge branch 'main' into 7486_reduce-tooltip-over-group
LucioChavezFuentes Apr 27, 2022
7895f01
remove unneeded wrapperView initializing
LucioChavezFuentes Apr 27, 2022
e076b95
move wrapper width condition to getTooltipStyles
LucioChavezFuentes May 2, 2022
6ade224
move maxWidth before optional parameters
LucioChavezFuentes May 2, 2022
e098176
update comment and change offsetWidth to measure function
LucioChavezFuentes May 3, 2022
89c5781
revert to offsetWidth, minor comment changes
LucioChavezFuentes May 4, 2022
34231f9
change on comments
LucioChavezFuentes May 9, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/components/MultipleAvatars.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import {Image, View} from 'react-native';
import _ from 'underscore';
import styles from '../styles/styles';
import variables from '../styles/variables';
import Avatar from './Avatar';
import Tooltip from './Tooltip';
import Text from './Text';
Expand Down Expand Up @@ -80,7 +81,7 @@ const MultipleAvatars = (props) => {
/>
</Tooltip>
) : (
<Tooltip text={props.avatarTooltips.slice(1).join(', ')} absolute>
<Tooltip text={props.avatarTooltips.slice(1).join(', ')} absolute numberOfLines={3} maxWidth={variables.sideBarWidth}>
<View
style={[singleAvatarStyles, styles.alignItemsCenter, styles.justifyContentCenter]}
>
Expand Down
139 changes: 88 additions & 51 deletions src/components/Tooltip/TooltipRenderedOnPageBody.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {memo} from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import {Animated, View} from 'react-native';
import ReactDOM from 'react-dom';
Expand All @@ -25,12 +25,6 @@ const propTypes = {
/** The Height of the tooltip wrapper */
wrapperHeight: PropTypes.number.isRequired,

/** The width of the tooltip itself */
tooltipWidth: PropTypes.number.isRequired,

/** The Height of the tooltip itself */
tooltipHeight: PropTypes.number.isRequired,

/** Any additional amount to manually adjust the horizontal position of the tooltip.
A positive value shifts the tooltip to the right, and a negative value shifts it to the left. */
shiftHorizontal: PropTypes.number.isRequired,
Expand All @@ -39,59 +33,102 @@ const propTypes = {
A positive value shifts the tooltip down, and a negative value shifts it up. */
shiftVertical: PropTypes.number.isRequired,

/** Callback to set the Ref to the Tooltip */
setTooltipRef: PropTypes.func.isRequired,

/** Text to be shown in the tooltip */
text: PropTypes.string.isRequired,

/** Callback to be used to calulate the width and height of tooltip */
measureTooltip: PropTypes.func.isRequired,
};
/** Number of pixels to set max-width on tooltip */
maxWidth: PropTypes.number,

/** Maximum number of lines to set on tooltip */
numberOfLines: PropTypes.number,

const defaultProps = {};

const TooltipRenderedOnPageBody = (props) => {
const {
animationStyle,
tooltipWrapperStyle,
tooltipTextStyle,
pointerWrapperStyle,
pointerStyle,
} = getTooltipStyles(
props.animation,
props.windowWidth,
props.xOffset,
props.yOffset,
props.wrapperWidth,
props.wrapperHeight,
props.tooltipWidth,
props.tooltipHeight,
props.shiftHorizontal,
props.shiftVertical,
);
return ReactDOM.createPortal(
<Animated.View
ref={props.setTooltipRef}
onLayout={props.measureTooltip}
style={[tooltipWrapperStyle, animationStyle]}
>
<Text style={tooltipTextStyle} numberOfLines={1}>{props.text}</Text>
<View style={pointerWrapperStyle}>
<View style={pointerStyle} />
</View>
</Animated.View>,
document.querySelector('body'),
);
};

TooltipRenderedOnPageBody.propTypes = propTypes;
TooltipRenderedOnPageBody.defaultProps = defaultProps;
TooltipRenderedOnPageBody.displayName = 'TooltipRenderedOnPageBody';
const defaultProps = {
maxWidth: undefined,
numberOfLines: undefined,
};

// Props will change frequently.
// On every tooltip hover, we update the position in state which will result in re-rendering.
// We also update the state on layout changes which will be triggered often.
// There will be n number of tooltip components in the page.
// Its good to memorize this one.
export default memo(TooltipRenderedOnPageBody);
class TooltipRenderedOnPageBody extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
// Set maxWidth as initial so we can get width of word wrapped text
tooltipTextWidth: this.props.maxWidth,

// The width and height of the tooltip itself
tooltipWidth: 0,
tooltipHeight: 0,
};

this.measureTooltip = this.measureTooltip.bind(this);
}

componentDidMount() {
if (!this.props.maxWidth) {
return;
}
this.setState({
tooltipTextWidth: this.textRef.offsetWidth,
});
}

/**
* Measure the size of the tooltip itself.
*
* @param {Object} nativeEvent
*/
measureTooltip({nativeEvent}) {
this.setState({
tooltipWidth: nativeEvent.layout.width,
tooltipHeight: nativeEvent.layout.height,
});
}

render() {
const {
animationStyle,
tooltipWrapperStyle,
tooltipTextStyle,
pointerWrapperStyle,
pointerStyle,
} = getTooltipStyles(
this.props.animation,
this.props.windowWidth,
this.props.xOffset,
this.props.yOffset,
this.props.wrapperWidth,
this.props.wrapperHeight,
this.state.tooltipWidth,
this.state.tooltipHeight,
this.props.shiftHorizontal,
this.props.shiftVertical,
this.state.tooltipTextWidth,
this.props.maxWidth,
);
return ReactDOM.createPortal(
<Animated.View
onLayout={this.measureTooltip}
style={[tooltipWrapperStyle, animationStyle]}
>
<Text numberOfLines={this.props.numberOfLines} style={tooltipTextStyle}>
<Text style={tooltipTextStyle} ref={ref => this.textRef = ref}>{this.props.text}</Text>
</Text>
<View style={pointerWrapperStyle}>
<View style={pointerStyle} />
</View>
</Animated.View>,
document.querySelector('body'),
);
}
}

TooltipRenderedOnPageBody.propTypes = propTypes;
TooltipRenderedOnPageBody.defaultProps = defaultProps;

export default TooltipRenderedOnPageBody;
25 changes: 2 additions & 23 deletions src/components/Tooltip/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,17 @@ class Tooltip extends PureComponent {
wrapperWidth: 0,
wrapperHeight: 0,

// The width and height of the tooltip itself
tooltipWidth: 0,
tooltipHeight: 0,
};

// The wrapper view containing the wrapped content along with the Tooltip itself.
this.wrapperView = null;

// The tooltip (popover) itself.
this.tooltip = null;

// Whether the tooltip is first tooltip to activate the TooltipSense
this.isTooltipSenseInitiator = false;
this.shouldStartShowAnimation = false;
this.animation = new Animated.Value(0);

this.getWrapperPosition = this.getWrapperPosition.bind(this);
this.measureTooltip = this.measureTooltip.bind(this);
this.showTooltip = this.showTooltip.bind(this);
this.hideTooltip = this.hideTooltip.bind(this);
}
Expand Down Expand Up @@ -86,18 +79,6 @@ class Tooltip extends PureComponent {
}));
}

/**
* Measure the size of the tooltip itself.
*
* @param {Object} nativeEvent
*/
measureTooltip({nativeEvent}) {
this.setState({
tooltipWidth: nativeEvent.layout.width,
tooltipHeight: nativeEvent.layout.height,
});
}

/**
* Display the tooltip in an animation.
*/
Expand Down Expand Up @@ -200,13 +181,11 @@ class Tooltip extends PureComponent {
yOffset={this.state.yOffset}
wrapperWidth={this.state.wrapperWidth}
wrapperHeight={this.state.wrapperHeight}
tooltipWidth={this.state.tooltipWidth}
tooltipHeight={this.state.tooltipHeight}
setTooltipRef={el => this.tooltip = el}
shiftHorizontal={_.result(this.props, 'shiftHorizontal')}
shiftVertical={_.result(this.props, 'shiftVertical')}
measureTooltip={this.measureTooltip}
text={this.props.text}
maxWidth={this.props.maxWidth}
numberOfLines={this.props.numberOfLines}
/>
)}
<Hoverable
Expand Down
9 changes: 9 additions & 0 deletions src/components/Tooltip/tooltipPropTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ const propTypes = {
/** Any additional amount to manually adjust the vertical position of the tooltip.
A positive value shifts the tooltip down, and a negative value shifts it up. */
shiftVertical: PropTypes.oneOfType([PropTypes.number, PropTypes.func]),

/** Number of pixels to set max-width on tooltip */
maxWidth: PropTypes.number,

/** Maximum number of lines to set on tooltip */
numberOfLines: PropTypes.number,

};

const defaultProps = {
Expand All @@ -32,6 +39,8 @@ const defaultProps = {
shiftVertical: 0,
containerStyles: [],
text: '',
maxWidth: undefined,
numberOfLines: undefined,
};

export {
Expand Down
11 changes: 11 additions & 0 deletions src/styles/getTooltipStyles.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ function computeHorizontalShift(windowWidth, xOffset, componentWidth, tooltipWid
* and a negative value shifts it to the left.
* @param {Number} [manualShiftVertical] - Any additional amount to manually shift the tooltip up or down.
* A positive value shifts it down, and a negative value shifts it up.
* @param {Number} [tooltipTextWidth] - Tooltip's inner text width
* @param {Number} [maxWidth] - Max-width for tooltip's wrapper
* @returns {Object}
*/
export default function getTooltipStyles(
Expand All @@ -80,6 +82,8 @@ export default function getTooltipStyles(
tooltipHeight,
manualShiftHorizontal = 0,
manualShiftVertical = 0,
tooltipTextWidth,
maxWidth,
) {
// Determine if the tooltip should display below the wrapped component.
// If a tooltip will try to render within GUTTER_WIDTH logical pixels of the top of the screen,
Expand Down Expand Up @@ -109,6 +113,11 @@ export default function getTooltipStyles(
...tooltipVerticalPadding,
...spacing.ph2,
zIndex: variables.tooltipzIndex,
maxWidth: tooltipTextWidth >= maxWidth
? maxWidth

// Sum left and right padding
: tooltipTextWidth + (spacing.ph2.paddingHorizontal * 2),

// Because it uses fixed positioning, the top-left corner of the tooltip is aligned
// with the top-left corner of the window by default.
Expand Down Expand Up @@ -144,6 +153,8 @@ export default function getTooltipStyles(
color: themeColors.textReversed,
fontFamily: fontFamily.GTA,
fontSize: tooltipFontSize,
overflowWrap: 'normal',
overflow: 'hidden',
},
pointerWrapperStyle: {
position: 'fixed',
Expand Down