Skip to content
Merged
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
43 changes: 23 additions & 20 deletions src/components/Tooltip/BaseGenericTooltip/index.native.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {Portal} from '@gorhom/portal';
import React, {useMemo, useRef, useState} from 'react';
import {InteractionManager, View} from 'react-native';
import {View} from 'react-native';
// eslint-disable-next-line no-restricted-imports
import type {View as RNView} from 'react-native';
import Animated, {useAnimatedStyle} from 'react-native-reanimated';
import Animated, {useAnimatedStyle, useSharedValue} from 'react-native-reanimated';
import TransparentOverlay from '@components/AutoCompleteSuggestions/AutoCompleteSuggestionsPortal/TransparentOverlay/TransparentOverlay';
import Text from '@components/Text';
import useStyleUtils from '@hooks/useStyleUtils';
Expand Down Expand Up @@ -40,10 +40,12 @@ function BaseGenericTooltip({
// The width of tooltip's inner content. Has to be undefined in the beginning
// as a width of 0 will cause the content to be rendered of a width of 0,
// which prevents us from measuring it correctly.
const [contentMeasuredWidth, setContentMeasuredWidth] = useState<number>();
const [contentMeasuredWidthState, setContentMeasuredWidth] = useState<number>();
const contentMeasuredWidthAnimated = useSharedValue<number>(0);

// The height of tooltip's wrapper.
const [wrapperMeasuredHeight, setWrapperMeasuredHeight] = useState<number>();
const [wrapperMeasuredHeightState, setWrapperMeasuredHeight] = useState<number>();
const wrapperMeasuredHeightAnimated = useSharedValue<number>(0);
const rootWrapper = useRef<RNView>(null);

const StyleUtils = useStyleUtils();
Expand All @@ -58,8 +60,8 @@ function BaseGenericTooltip({
tooltipTargetWidth: targetWidth,
tooltipTargetHeight: targetHeight,
maxWidth,
tooltipContentWidth: contentMeasuredWidth,
tooltipWrapperHeight: wrapperMeasuredHeight,
tooltipContentWidth: contentMeasuredWidthState,
tooltipWrapperHeight: wrapperMeasuredHeightState,
manualShiftHorizontal: shiftHorizontal,
manualShiftVertical: shiftVertical,
shouldForceRenderingBelow,
Expand All @@ -75,8 +77,8 @@ function BaseGenericTooltip({
targetWidth,
targetHeight,
maxWidth,
contentMeasuredWidth,
wrapperMeasuredHeight,
contentMeasuredWidthState,
wrapperMeasuredHeightState,
shiftHorizontal,
shiftVertical,
shouldForceRenderingBelow,
Expand All @@ -86,7 +88,11 @@ function BaseGenericTooltip({
);

const animationStyle = useAnimatedStyle(() => {
return StyleUtils.getTooltipAnimatedStyles({tooltipContentWidth: contentMeasuredWidth, tooltipWrapperHeight: wrapperMeasuredHeight, currentSize: animation});
return StyleUtils.getTooltipAnimatedStyles({
tooltipContentWidth: contentMeasuredWidthAnimated.get(),
tooltipWrapperHeight: wrapperMeasuredHeightAnimated.get(),
currentSize: animation,
});
});

let content;
Expand All @@ -110,20 +116,17 @@ function BaseGenericTooltip({
ref={rootWrapper}
style={[rootWrapperStyle, animationStyle]}
onLayout={(e) => {
const {height} = e.nativeEvent.layout;
if (height === wrapperMeasuredHeight) {
const {height, width} = e.nativeEvent.layout;
if (height === wrapperMeasuredHeightAnimated.get()) {
return;
}
// To avoid unnecessary re-renders of the content container when passing state values to useAnimatedStyle,
// we use SharedValue for managing content and wrapper measurements.
contentMeasuredWidthAnimated.set(width);
wrapperMeasuredHeightAnimated.set(height);

setContentMeasuredWidth(width);
setWrapperMeasuredHeight(height);
// When tooltip is used inside an animated view (e.g. popover), we need to wait for the animation to finish before measuring content.
const target = e.target;
setTimeout(() => {
InteractionManager.runAfterInteractions(() => {
target.measure((x, y, width) => {
setContentMeasuredWidth(width);
});
});
}, CONST.ANIMATED_TRANSITION);
}}
>
{content}
Expand Down