-
Notifications
You must be signed in to change notification settings - Fork 3.1k
/
Copy pathindex.js
129 lines (120 loc) · 5.71 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import _ from 'underscore';
import React, {Fragment, PureComponent} from 'react';
import {View} from 'react-native';
import {propTypes, defaultProps} from './displayNamesPropTypes';
import styles from '../../styles/styles';
import Tooltip from '../Tooltip';
import Text from '../Text';
import UserDetailsTooltip from '../UserDetailsTooltip';
class DisplayNames extends PureComponent {
constructor(props) {
super(props);
this.containerRef = null;
this.childRefs = [];
this.state = {
isEllipsisActive: false,
};
this.setContainerLayout = this.setContainerLayout.bind(this);
this.getTooltipShiftX = this.getTooltipShiftX.bind(this);
}
componentDidMount() {
this.setState({
isEllipsisActive: this.containerRef && this.containerRef.offsetWidth && this.containerRef.scrollWidth && this.containerRef.offsetWidth < this.containerRef.scrollWidth,
});
}
/**
* Set the container layout for post calculations
*
* @param {*} {nativeEvent}
*/
setContainerLayout({nativeEvent}) {
this.containerLayout = nativeEvent.layout;
}
/**
* We may need to shift the Tooltip horizontally as some of the inline text wraps well with ellipsis,
* but their container node overflows the parent view which causes the tooltip to be misplaced.
*
* So we shift it by calculating it as follows:
* 1. We get the container layout and take the Child inline text node.
* 2. Now we get the tooltip original position.
* 3. If inline node's right edge is overflowing the container's right edge, we set the tooltip to the center
* of the distance between the left edge of the inline node and right edge of the container.
* @param {Number} index Used to get the Ref to the node at the current index
* @returns {Number} Distance to shift the tooltip horizontally
*/
getTooltipShiftX(index) {
// Only shift the tooltip in case the containerLayout or Refs to the text node are available
if (!this.containerLayout || !this.childRefs[index]) {
return;
}
const {width: containerWidth, left: containerLeft} = this.containerLayout;
// We have to return the value as Number so we can't use `measureWindow` which takes a callback
const {width: textNodeWidth, left: textNodeLeft} = this.childRefs[index].getBoundingClientRect();
const tooltipX = textNodeWidth / 2 + textNodeLeft;
const containerRight = containerWidth + containerLeft;
const textNodeRight = textNodeWidth + textNodeLeft;
const newToolX = textNodeLeft + (containerRight - textNodeLeft) / 2;
// When text right end is beyond the Container right end
return textNodeRight > containerRight ? -(tooltipX - newToolX) : 0;
}
render() {
if (!this.props.tooltipEnabled) {
// No need for any complex text-splitting, just return a simple Text component
return (
<Text
style={[...this.props.textStyles, this.props.numberOfLines === 1 ? styles.pre : styles.preWrap]}
numberOfLines={this.props.numberOfLines}
>
{this.props.fullTitle}
</Text>
);
}
return (
// Tokenization of string only support 1 numberOfLines on Web
<Text
style={[...this.props.textStyles, styles.pRelative]}
onLayout={this.setContainerLayout}
numberOfLines={1}
ref={(el) => (this.containerRef = el)}
>
{this.props.shouldUseFullTitle
? this.props.fullTitle
: _.map(this.props.displayNamesWithTooltips, ({displayName, accountID, avatar, login}, index) => (
<Fragment key={index}>
<UserDetailsTooltip
key={index}
accountID={accountID}
fallbackUserDetails={{
avatar,
login,
displayName,
}}
shiftHorizontal={() => this.getTooltipShiftX(index)}
>
{/* // We need to get the refs to all the names which will be used to correct
the horizontal position of the tooltip */}
<Text
ref={(el) => (this.childRefs[index] = el)}
style={[...this.props.textStyles, styles.pre]}
>
{displayName}
</Text>
</UserDetailsTooltip>
{index < this.props.displayNamesWithTooltips.length - 1 && <Text style={this.props.textStyles}>, </Text>}
</Fragment>
))}
{this.props.displayNamesWithTooltips.length > 1 && Boolean(this.state.isEllipsisActive) && (
<View style={styles.displayNameTooltipEllipsis}>
<Tooltip text={this.props.fullTitle}>
{/* There is some Gap for real ellipsis so we are adding 4 `.` to cover */}
<Text>....</Text>
</Tooltip>
</View>
)}
</Text>
);
}
}
DisplayNames.propTypes = propTypes;
DisplayNames.defaultProps = defaultProps;
export default DisplayNames;