Skip to content

Commit

Permalink
refactor tooltip to fix double focusable component
Browse files Browse the repository at this point in the history
  • Loading branch information
bernhardoj committed Mar 16, 2023
1 parent c40148b commit 24381ed
Show file tree
Hide file tree
Showing 18 changed files with 160 additions and 176 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ const BaseAnchorForCommentsOnly = (props) => {
onPressIn={props.onPressIn}
onPressOut={props.onPressOut}
>
<Tooltip containerStyles={[styles.dInline]} text={Str.isValidEmail(props.displayName) ? '' : props.href}>
<Tooltip text={Str.isValidEmail(props.displayName) ? '' : props.href}>
<Text
ref={el => linkRef = el}
style={StyleSheet.flatten([props.style, defaultTextStyle])}
Expand Down
8 changes: 4 additions & 4 deletions src/components/AvatarWithIndicator.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ const AvatarWithIndicator = (props) => {
const shouldShowIndicator = _.some(errorCheckingMethods, errorCheckingMethod => errorCheckingMethod());

return (
<View style={[isLarge ? styles.avatarLarge : styles.sidebarAvatar]}>
<Tooltip text={props.tooltipText}>
<Tooltip text={props.tooltipText}>
<View style={[isLarge ? styles.avatarLarge : styles.sidebarAvatar]}>
<Avatar
imageStyles={[isLarge ? styles.avatarLarge : null]}
source={props.source}
Expand All @@ -95,8 +95,8 @@ const AvatarWithIndicator = (props) => {
{shouldShowIndicator && (
<View style={StyleSheet.flatten(indicatorStyles)} />
)}
</Tooltip>
</View>
</View>
</Tooltip>
);
};

Expand Down
1 change: 0 additions & 1 deletion src/components/DisplayNames/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ class DisplayNames extends PureComponent {
<Tooltip
key={index}
text={tooltip}
containerStyles={[styles.dInline]}
shiftHorizontal={() => this.getTooltipShiftX(index)}
>
{/* // We need to get the refs to all the names which will be used to correct
Expand Down
29 changes: 14 additions & 15 deletions src/components/EmojiPicker/CategoryShortcutButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,29 +33,28 @@ class CategoryShortcutButton extends PureComponent {

render() {
return (
<Pressable
onPress={this.props.onPress}
onHoverIn={() => this.setState({isHighlighted: true})}
onHoverOut={() => this.setState({isHighlighted: false})}
style={({pressed}) => ([
StyleUtils.getButtonBackgroundColorStyle(getButtonState(false, pressed)),
styles.categoryShortcutButton,
this.state.isHighlighted && styles.emojiItemHighlighted,
])}
<Tooltip
text={this.props.translate(`emojiPicker.headers.${this.props.code}`)}
shiftVertical={-4}
>
<Tooltip
containerStyles={[styles.flex1, styles.alignSelfStretch, styles.alignItemsCenter, styles.justifyContentCenter]}
text={this.props.translate(`emojiPicker.headers.${this.props.code}`)}
shiftVertical={-4}
<Pressable
onPress={this.props.onPress}
onHoverIn={() => this.setState({isHighlighted: true})}
onHoverOut={() => this.setState({isHighlighted: false})}
style={({pressed}) => ([
StyleUtils.getButtonBackgroundColorStyle(getButtonState(false, pressed)),
styles.categoryShortcutButton,
this.state.isHighlighted && styles.emojiItemHighlighted,
])}
>
<Icon
fill={themeColors.icon}
src={this.props.icon}
height={variables.iconSizeNormal}
width={variables.iconSizeNormal}
/>
</Tooltip>
</Pressable>
</Pressable>
</Tooltip>
);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/FloatingActionButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class FloatingActionButton extends PureComponent {
});

return (
<Tooltip absolute text={this.props.translate('common.new')}>
<Tooltip text={this.props.translate('common.new')}>
<View style={styles.floatingActionButtonContainer}>
<AnimatedPressable
ref={el => this.fabPressable = el}
Expand Down
103 changes: 45 additions & 58 deletions src/components/Hoverable/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,68 +55,55 @@ class Hoverable extends Component {
}

render() {
if (this.props.absolute && React.isValidElement(this.props.children)) {
return React.cloneElement(React.Children.only(this.props.children), {
ref: (el) => {
this.wrapperView = el;

// Call the original ref, if any
const {ref} = this.props.children;
if (_.isFunction(ref)) {
ref(el);
}
},
onMouseEnter: (el) => {
this.setIsHovered(true);

// Call the original onMouseEnter, if any
const {onMouseEnter} = this.props.children;
if (_.isFunction(onMouseEnter)) {
onMouseEnter(el);
}
},
onMouseLeave: (el) => {
this.setIsHovered(false);
const child = _.isFunction(this.props.children)
? this.props.children(this.state.isHovered)
: this.props.children

// Call the original onMouseLeave, if any
const {onMouseLeave} = this.props.children;
if (_.isFunction(onMouseLeave)) {
onMouseLeave(el);
}
},
onBlur: (el) => {
if (!this.wrapperView.contains(el.relatedTarget)) {
this.setIsHovered(false);
}

// Call the original onBlur, if any
const {onBlur} = this.props.children;
if (_.isFunction(onBlur)) {
onBlur(el);
}
},
});
if (!React.isValidElement(child)) {
throw Error("Children is not a valid element.");
}
return (
<View
style={this.props.containerStyles}
ref={el => this.wrapperView = el}
onMouseEnter={() => this.setIsHovered(true)}
onMouseLeave={() => this.setIsHovered(false)}
onBlur={(el) => {
if (this.wrapperView.contains(el.relatedTarget)) {
return;
}

return React.cloneElement(React.Children.only(child), {
ref: (el) => {
this.wrapperView = el;

// Call the original ref, if any
const {ref} = child;
if (_.isFunction(ref)) {
ref(el);
}
},
onMouseEnter: (el) => {
console.log("ENTER")
this.setIsHovered(true);

// Call the original onMouseEnter, if any
const {onMouseEnter} = child;
if (_.isFunction(onMouseEnter)) {
onMouseEnter(el);
}
},
onMouseLeave: (el) => {
this.setIsHovered(false);

// Call the original onMouseLeave, if any
const {onMouseLeave} = child;
if (_.isFunction(onMouseLeave)) {
onMouseLeave(el);
}
},
onBlur: (el) => {
if (!this.wrapperView.contains(el.relatedTarget)) {
this.setIsHovered(false);
}}
>
{ // If this.props.children is a function, call it to provide the hover state to the children.
_.isFunction(this.props.children)
? this.props.children(this.state.isHovered)
: this.props.children
}
</View>
);

// Call the original onBlur, if any
const {onBlur} = child;
if (_.isFunction(onBlur)) {
onBlur(el);
}
},
});
}
}

Expand Down
14 changes: 7 additions & 7 deletions src/components/MultipleAvatars.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,17 +69,17 @@ const MultipleAvatars = (props) => {

if (props.icons.length === 1 && !props.shouldStackHorizontally) {
return (
<View style={avatarContainerStyles}>
<Tooltip text={props.avatarTooltips[0]}>
<Tooltip text={props.avatarTooltips[0]}>
<View style={avatarContainerStyles}>
<Avatar
source={props.icons[0].source}
size={props.size}
fill={themeColors.iconSuccessFill}
name={props.icons[0].name}
type={props.icons[0].type}
/>
</Tooltip>
</View>
</View>
</Tooltip>
);
}

Expand Down Expand Up @@ -127,7 +127,7 @@ const MultipleAvatars = (props) => {
<View
style={singleAvatarStyles}
>
<Tooltip text={props.avatarTooltips[0]} absolute>
<Tooltip text={props.avatarTooltips[0]}>
{/* View is necessary for tooltip to show for multiple avatars in LHN */}
<View>
<Avatar
Expand All @@ -145,7 +145,7 @@ const MultipleAvatars = (props) => {
style={secondAvatarStyles}
>
{props.icons.length === 2 ? (
<Tooltip text={props.avatarTooltips[1]} absolute>
<Tooltip text={props.avatarTooltips[1]}>
<View>
<Avatar
source={props.icons[1].source || props.fallbackIcon}
Expand All @@ -159,7 +159,7 @@ const MultipleAvatars = (props) => {
</View>
</Tooltip>
) : (
<Tooltip text={props.avatarTooltips.slice(1).join(', ')} absolute>
<Tooltip text={props.avatarTooltips.slice(1).join(', ')}>
<View
style={[singleAvatarStyles, styles.alignItemsCenter, styles.justifyContentCenter]}
>
Expand Down
6 changes: 1 addition & 5 deletions src/components/OptionRow.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,7 @@ class OptionRow extends Component {
errors={this.props.option.allReportErrors}
shouldShowErrorMessages={false}
>
<Hoverable
containerStyles={[
this.props.isDisabled ? styles.userSelectNone : null,
]}
>
<Hoverable>
{hovered => (
<TouchableOpacity
ref={el => touchableRef = el}
Expand Down
2 changes: 1 addition & 1 deletion src/components/Reactions/AddReactionBubble.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ const AddReactionBubble = (props) => {
};

return (
<Tooltip text={props.translate('reportActionContextMenu.addReactionTooltip')} focusable={false}>
<Tooltip text={props.translate('reportActionContextMenu.addReactionTooltip')}>
<Pressable
ref={ref}
style={({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@ const propTypes = {
const BaseQuickEmojiReactions = props => (
<View style={styles.quickReactionsContainer}>
{_.map(CONST.QUICK_REACTIONS, emoji => (

// Note: focus is handled by the Pressable component in EmojiReactionBubble
<Tooltip text={`:${emoji.name}:`} key={emoji.name} focusable={false}>
<Tooltip text={`:${emoji.name}:`} key={emoji.name}>
<EmojiReactionBubble
emojiName={emoji.name}
emojiCodes={[getPreferredEmojiCode(emoji, props.preferredSkinTone)]}
Expand Down
2 changes: 1 addition & 1 deletion src/components/ReportWelcomeText.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ const ReportWelcomeText = (props) => {
displayName, pronouns, tooltip,
}, index) => (
<Text key={`${displayName}${pronouns}${index}`}>
<Tooltip text={tooltip} containerStyles={[styles.dInline]}>
<Tooltip text={tooltip}>
<Text style={[styles.textStrong]} onPress={() => Navigation.navigate(ROUTES.getDetailsRoute(participants[index]))}>
{displayName}
</Text>
Expand Down
32 changes: 17 additions & 15 deletions src/components/SubscriptAvatar.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,29 +42,31 @@ const defaultProps = {
const SubscriptAvatar = props => (
<View style={props.size === CONST.AVATAR_SIZE.SMALL ? styles.emptyAvatarSmall : styles.emptyAvatar}>
<Tooltip text={props.mainTooltip}>
<Avatar
source={props.mainAvatar.source}
size={props.size === CONST.AVATAR_SIZE.SMALL ? CONST.AVATAR_SIZE.SMALL : CONST.AVATAR_SIZE.DEFAULT}
name={props.mainAvatar.name}
type={props.mainAvatar.type}
/>
<View>
<Avatar
source={props.mainAvatar.source}
size={props.size === CONST.AVATAR_SIZE.SMALL ? CONST.AVATAR_SIZE.SMALL : CONST.AVATAR_SIZE.DEFAULT}
name={props.mainAvatar.name}
type={props.mainAvatar.type}
/>
</View>
</Tooltip>
<View style={[
props.size === CONST.AVATAR_SIZE.SMALL ? styles.secondAvatarSubscriptCompact : styles.secondAvatarSubscript,
StyleUtils.getBackgroundAndBorderStyle(props.backgroundColor),
StyleUtils.getAvatarBorderStyle(props.size, props.secondaryAvatar.type),
]}
>
<Tooltip text={props.secondaryTooltip}>
<Tooltip text={props.secondaryTooltip}>
<View style={[
props.size === CONST.AVATAR_SIZE.SMALL ? styles.secondAvatarSubscriptCompact : styles.secondAvatarSubscript,
StyleUtils.getBackgroundAndBorderStyle(props.backgroundColor),
StyleUtils.getAvatarBorderStyle(props.size, props.secondaryAvatar.type),
]}
>
<Avatar
source={props.secondaryAvatar.source}
size={props.size === CONST.AVATAR_SIZE.SMALL ? CONST.AVATAR_SIZE.SMALL_SUBSCRIPT : CONST.AVATAR_SIZE.SUBSCRIPT}
fill={themeColors.iconSuccessFill}
name={props.secondaryAvatar.name}
type={props.secondaryAvatar.type}
/>
</Tooltip>
</View>
</View>
</Tooltip>
</View>
);

Expand Down
Loading

0 comments on commit 24381ed

Please sign in to comment.