Skip to content

Commit

Permalink
fix: tooltips not working as expected (#3765)
Browse files Browse the repository at this point in the history
  • Loading branch information
pac-guerreiro authored Jun 26, 2023
1 parent 671e363 commit c724ad9
Show file tree
Hide file tree
Showing 6 changed files with 408 additions and 165 deletions.
30 changes: 20 additions & 10 deletions example/src/Examples/TooltipExample.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import * as React from 'react';
import { Platform, StyleSheet } from 'react-native';
import { Platform, StyleSheet, View } from 'react-native';

import type { StackNavigationProp } from '@react-navigation/stack';
import {
Appbar,
Avatar,
Banner,
FAB,
List,
Expand Down Expand Up @@ -43,12 +44,6 @@ const TooltipExample = ({ navigation }: Props) => {
});
});

const renderFAB = () => {
return (
<FAB size="medium" icon="plus" onPress={() => {}} style={[styles.fab]} />
);
};

return (
<>
<ScreenWrapper>
Expand All @@ -72,8 +67,19 @@ const TooltipExample = ({ navigation }: Props) => {
</Tooltip>
</ToggleButton.Row>
</List.Section>

<View style={styles.avatarContainer}>
<Tooltip title="Username">
<Avatar.Text label="U" />
</Tooltip>
</View>
</ScreenWrapper>
<Tooltip title="Press Me">{renderFAB()}</Tooltip>

<View style={styles.fabContainer}>
<Tooltip title="Press Me">
<FAB size="medium" icon="plus" onPress={() => {}} />
</Tooltip>
</View>
</>
);
};
Expand All @@ -83,10 +89,14 @@ TooltipExample.title = 'Tooltip';
export default TooltipExample;

const styles = StyleSheet.create({
fab: {
position: 'absolute',
avatarContainer: {
margin: 16,
width: 64,
},
fabContainer: {
margin: 16,
right: 0,
position: 'absolute',
bottom: 0,
},
toggleButtonRow: {
Expand Down
1 change: 1 addition & 0 deletions src/components/FAB/FAB.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ const FAB = forwardRef<View, Props>(
accessibilityState={newAccessibilityState}
testID={testID}
style={{ borderRadius }}
{...rest}
>
<View
style={[styles.content, label ? extendedStyle : fabStyle]}
Expand Down
12 changes: 8 additions & 4 deletions src/components/Tooltip/Tooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,15 @@ const Tooltip = ({
clearTimeout(hideTooltipTimer.current);
}

showTooltipTimer.current = setTimeout(() => {
if (isWeb) {
showTooltipTimer.current = setTimeout(() => {
touched.current = true;
setVisible(true);
}, enterTouchDelay) as unknown as NodeJS.Timeout;
} else {
touched.current = true;
setVisible(true);
}, enterTouchDelay) as unknown as NodeJS.Timeout;
}
};

const handleTouchEnd = () => {
Expand Down Expand Up @@ -179,7 +184,7 @@ const Tooltip = ({
backgroundColor: theme.isV3
? theme.colors.onSurface
: theme.colors.tooltip,
...getTooltipPosition(measurement as Measurement),
...getTooltipPosition(measurement as Measurement, children),
borderRadius: theme.roundness,
...(measurement.measured ? styles.visible : styles.hidden),
},
Expand Down Expand Up @@ -229,7 +234,6 @@ const styles = StyleSheet.create({
},
pressContainer: {
cursor: 'default',
alignSelf: 'flex-start',
} as ViewStyle,
});

Expand Down
62 changes: 53 additions & 9 deletions src/components/Tooltip/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Dimensions, LayoutRectangle } from 'react-native';
import { Dimensions, LayoutRectangle, ViewStyle } from 'react-native';

type ChildrenMeasurement = {
width: number;
Expand Down Expand Up @@ -51,7 +51,12 @@ const getTooltipXPosition = (
{ pageX: childrenX, width: childrenWidth }: ChildrenMeasurement,
{ width: tooltipWidth }: TooltipLayout
): number => {
const center = childrenX + (childrenWidth - tooltipWidth) / 2;
// when the children use position absolute the childrenWidth is measured as 0,
// so it's best to anchor the tooltip at the start of the children
const center =
childrenWidth > 0
? childrenX + (childrenWidth - tooltipWidth) / 2
: childrenX;

if (overflowLeft(center)) return childrenX;

Expand All @@ -71,15 +76,54 @@ const getTooltipYPosition = (
return childrenY + childrenHeight;
};

export const getTooltipPosition = ({
children,
tooltip,
measured,
}: Measurement): {} | { left: number; top: number } => {
const getChildrenMeasures = (
style: ViewStyle | Array<ViewStyle>,
measures: ChildrenMeasurement
): ChildrenMeasurement => {
const { position, top, bottom, left, right } = Array.isArray(style)
? style.reduce((acc, current) => ({ ...acc, ...current }))
: style;

if (position === 'absolute') {
let pageX = 0;
let pageY = measures.pageY;
let height = 0;
let width = 0;
if (typeof left === 'number') {
pageX = left;
width = 0;
}
if (typeof right === 'number') {
pageX = measures.width - right;
width = 0;
}
if (typeof top === 'number') {
pageY = pageY + top;
}
if (typeof bottom === 'number') {
pageY = pageY - bottom;
}

return { pageX, pageY, width, height };
}

return measures;
};

export const getTooltipPosition = (
{ children, tooltip, measured }: Measurement,
component: React.ReactElement<{
style: ViewStyle | Array<ViewStyle> | undefined | null;
}>
): {} | { left: number; top: number } => {
if (!measured) return {};
let measures = children;
if (component.props.style) {
measures = getChildrenMeasures(component.props.style, children);
}

return {
left: getTooltipXPosition(children, tooltip),
top: getTooltipYPosition(children, tooltip),
left: getTooltipXPosition(measures, tooltip),
top: getTooltipYPosition(measures, tooltip),
};
};
Loading

0 comments on commit c724ad9

Please sign in to comment.