Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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 @@ -286,6 +286,7 @@ const FAB = forwardRef<View, Props>(
accessibilityState={newAccessibilityState}
testID={testID}
style={{ borderRadius }}
{...rest}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this change?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pac-guerreiro remember why it was added there?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like without added {...rest}, Tooltip is not displayed over the FAB on the web.

>
<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(() => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if I want to have an enterTouchDelay on mobile? Since the base component is a Pressable now, would it be possible to replace this prop enterTouchDelay with delayLongPress?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing prop would be a breaking change and require releasing new version. enterTouchDelay is translated to delayLongPress on mobile:

delayLongPress: enterTouchDelay,

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