From aa59e9053d6b0c9a6368621de64a171f9e4aeca6 Mon Sep 17 00:00:00 2001
From: Linh Vo <vovanlinh29546@gmail.com>
Date: Wed, 25 Dec 2024 14:05:58 +0700
Subject: [PATCH 1/3] fix: android native tooltip appears broken

---
 .../BaseGenericTooltip/index.native.tsx       | 38 +++++++++----------
 1 file changed, 18 insertions(+), 20 deletions(-)

diff --git a/src/components/Tooltip/BaseGenericTooltip/index.native.tsx b/src/components/Tooltip/BaseGenericTooltip/index.native.tsx
index b48cb55ccea1..326d8dbf042b 100644
--- a/src/components/Tooltip/BaseGenericTooltip/index.native.tsx
+++ b/src/components/Tooltip/BaseGenericTooltip/index.native.tsx
@@ -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';
@@ -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 contentMeasuredWidth = useSharedValue<number>(0);
 
     // The height of tooltip's wrapper.
-    const [wrapperMeasuredHeight, setWrapperMeasuredHeight] = useState<number>();
+    const [wrapperMeasuredHeightState, setWrapperMeasuredHeight] = useState<number>();
+    const wrapperMeasuredHeight = useSharedValue<number>(0);
     const rootWrapper = useRef<RNView>(null);
 
     const StyleUtils = useStyleUtils();
@@ -58,8 +60,8 @@ function BaseGenericTooltip({
                 tooltipTargetWidth: targetWidth,
                 tooltipTargetHeight: targetHeight,
                 maxWidth,
-                tooltipContentWidth: contentMeasuredWidth,
-                tooltipWrapperHeight: wrapperMeasuredHeight,
+                tooltipContentWidth: contentMeasuredWidthState,
+                tooltipWrapperHeight: wrapperMeasuredHeightState,
                 manualShiftHorizontal: shiftHorizontal,
                 manualShiftVertical: shiftVertical,
                 shouldForceRenderingBelow,
@@ -75,8 +77,8 @@ function BaseGenericTooltip({
             targetWidth,
             targetHeight,
             maxWidth,
-            contentMeasuredWidth,
-            wrapperMeasuredHeight,
+            contentMeasuredWidthState,
+            wrapperMeasuredHeightState,
             shiftHorizontal,
             shiftVertical,
             shouldForceRenderingBelow,
@@ -86,7 +88,7 @@ function BaseGenericTooltip({
     );
 
     const animationStyle = useAnimatedStyle(() => {
-        return StyleUtils.getTooltipAnimatedStyles({tooltipContentWidth: contentMeasuredWidth, tooltipWrapperHeight: wrapperMeasuredHeight, currentSize: animation});
+        return StyleUtils.getTooltipAnimatedStyles({tooltipContentWidth: contentMeasuredWidth.get(), tooltipWrapperHeight: wrapperMeasuredHeight.get(), currentSize: animation});
     });
 
     let content;
@@ -110,20 +112,16 @@ 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 === wrapperMeasuredHeight.get()) {
                         return;
                     }
+                    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);
+                    // To avoid unnecessary re-renders of the content container when passing state values to useAnimatedStyle,
+                    // we use SharedValue for managing content and wrapper measurements.
+                    contentMeasuredWidth.set(width);
+                    wrapperMeasuredHeight.set(height);
                 }}
             >
                 {content}

From 95e067ce3064eadec15d2b02609919adeaf69c34 Mon Sep 17 00:00:00 2001
From: Linh Vo <vovanlinh29546@gmail.com>
Date: Wed, 25 Dec 2024 14:30:05 +0700
Subject: [PATCH 2/3] fix: rename animated value

---
 .../BaseGenericTooltip/index.native.tsx       | 35 ++++++++++---------
 1 file changed, 18 insertions(+), 17 deletions(-)

diff --git a/src/components/Tooltip/BaseGenericTooltip/index.native.tsx b/src/components/Tooltip/BaseGenericTooltip/index.native.tsx
index 326d8dbf042b..e798fb6fca9b 100644
--- a/src/components/Tooltip/BaseGenericTooltip/index.native.tsx
+++ b/src/components/Tooltip/BaseGenericTooltip/index.native.tsx
@@ -1,14 +1,14 @@
-import {Portal} from '@gorhom/portal';
-import React, {useMemo, useRef, useState} from 'react';
-import {View} from 'react-native';
+import { Portal } from '@gorhom/portal';
+import React, { useMemo, useRef, useState } from 'react';
+import { View } from 'react-native';
 // eslint-disable-next-line no-restricted-imports
-import type {View as RNView} from 'react-native';
-import Animated, {useAnimatedStyle, useSharedValue} from 'react-native-reanimated';
+import type { View as RNView } from 'react-native';
+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';
 import CONST from '@src/CONST';
-import type {BaseGenericTooltipProps} from './types';
+import type { BaseGenericTooltipProps } from './types';
 
 // Props will change frequently.
 // On every tooltip hover, we update the position in state which will result in re-rendering.
@@ -35,21 +35,21 @@ function BaseGenericTooltip({
     },
     wrapperStyle = {},
     shouldUseOverlay = false,
-    onHideTooltip = () => {},
+    onHideTooltip = () => { },
 }: BaseGenericTooltipProps) {
     // 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 [contentMeasuredWidthState, setContentMeasuredWidth] = useState<number>();
-    const contentMeasuredWidth = useSharedValue<number>(0);
+    const contentMeasuredWidthAnimated = useSharedValue<number>(0);
 
     // The height of tooltip's wrapper.
     const [wrapperMeasuredHeightState, setWrapperMeasuredHeight] = useState<number>();
-    const wrapperMeasuredHeight = useSharedValue<number>(0);
+    const wrapperMeasuredHeightAnimated = useSharedValue<number>(0);
     const rootWrapper = useRef<RNView>(null);
 
     const StyleUtils = useStyleUtils();
-    const {rootWrapperStyle, textStyle, pointerWrapperStyle, pointerStyle} = useMemo(
+    const { rootWrapperStyle, textStyle, pointerWrapperStyle, pointerStyle } = useMemo(
         () =>
             StyleUtils.getTooltipStyles({
                 // eslint-disable-next-line react-compiler/react-compiler
@@ -88,7 +88,7 @@ function BaseGenericTooltip({
     );
 
     const animationStyle = useAnimatedStyle(() => {
-        return StyleUtils.getTooltipAnimatedStyles({tooltipContentWidth: contentMeasuredWidth.get(), tooltipWrapperHeight: wrapperMeasuredHeight.get(), currentSize: animation});
+        return StyleUtils.getTooltipAnimatedStyles({ tooltipContentWidth: contentMeasuredWidthAnimated.get(), tooltipWrapperHeight: wrapperMeasuredHeightAnimated.get(), currentSize: animation });
     });
 
     let content;
@@ -112,16 +112,17 @@ function BaseGenericTooltip({
                 ref={rootWrapper}
                 style={[rootWrapperStyle, animationStyle]}
                 onLayout={(e) => {
-                    const {height, width} = e.nativeEvent.layout;
-                    if (height === wrapperMeasuredHeight.get()) {
+                    const { height, width } = e.nativeEvent.layout;
+                    if (height === wrapperMeasuredHeightAnimated.get()) {
                         return;
                     }
-                    setContentMeasuredWidth(width);
-                    setWrapperMeasuredHeight(height);
                     // To avoid unnecessary re-renders of the content container when passing state values to useAnimatedStyle,
                     // we use SharedValue for managing content and wrapper measurements.
-                    contentMeasuredWidth.set(width);
-                    wrapperMeasuredHeight.set(height);
+                    contentMeasuredWidthAnimated.set(width);
+                    wrapperMeasuredHeightAnimated.set(height);
+
+                    setContentMeasuredWidth(width);
+                    setWrapperMeasuredHeight(height);
                 }}
             >
                 {content}

From 10812e3ae79c99888a4cff12ad4c8e7b6f5630d5 Mon Sep 17 00:00:00 2001
From: Linh Vo <vovanlinh29546@gmail.com>
Date: Wed, 25 Dec 2024 14:34:38 +0700
Subject: [PATCH 3/3] chore: prettier

---
 .../BaseGenericTooltip/index.native.tsx       | 24 +++++++++++--------
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/src/components/Tooltip/BaseGenericTooltip/index.native.tsx b/src/components/Tooltip/BaseGenericTooltip/index.native.tsx
index e798fb6fca9b..f695ebaf0ca3 100644
--- a/src/components/Tooltip/BaseGenericTooltip/index.native.tsx
+++ b/src/components/Tooltip/BaseGenericTooltip/index.native.tsx
@@ -1,14 +1,14 @@
-import { Portal } from '@gorhom/portal';
-import React, { useMemo, useRef, useState } from 'react';
-import { View } from 'react-native';
+import {Portal} from '@gorhom/portal';
+import React, {useMemo, useRef, useState} from 'react';
+import {View} from 'react-native';
 // eslint-disable-next-line no-restricted-imports
-import type { View as RNView } from 'react-native';
-import Animated, { useAnimatedStyle, useSharedValue } from 'react-native-reanimated';
+import type {View as RNView} from 'react-native';
+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';
 import CONST from '@src/CONST';
-import type { BaseGenericTooltipProps } from './types';
+import type {BaseGenericTooltipProps} from './types';
 
 // Props will change frequently.
 // On every tooltip hover, we update the position in state which will result in re-rendering.
@@ -35,7 +35,7 @@ function BaseGenericTooltip({
     },
     wrapperStyle = {},
     shouldUseOverlay = false,
-    onHideTooltip = () => { },
+    onHideTooltip = () => {},
 }: BaseGenericTooltipProps) {
     // 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,
@@ -49,7 +49,7 @@ function BaseGenericTooltip({
     const rootWrapper = useRef<RNView>(null);
 
     const StyleUtils = useStyleUtils();
-    const { rootWrapperStyle, textStyle, pointerWrapperStyle, pointerStyle } = useMemo(
+    const {rootWrapperStyle, textStyle, pointerWrapperStyle, pointerStyle} = useMemo(
         () =>
             StyleUtils.getTooltipStyles({
                 // eslint-disable-next-line react-compiler/react-compiler
@@ -88,7 +88,11 @@ function BaseGenericTooltip({
     );
 
     const animationStyle = useAnimatedStyle(() => {
-        return StyleUtils.getTooltipAnimatedStyles({ tooltipContentWidth: contentMeasuredWidthAnimated.get(), tooltipWrapperHeight: wrapperMeasuredHeightAnimated.get(), currentSize: animation });
+        return StyleUtils.getTooltipAnimatedStyles({
+            tooltipContentWidth: contentMeasuredWidthAnimated.get(),
+            tooltipWrapperHeight: wrapperMeasuredHeightAnimated.get(),
+            currentSize: animation,
+        });
     });
 
     let content;
@@ -112,7 +116,7 @@ function BaseGenericTooltip({
                 ref={rootWrapper}
                 style={[rootWrapperStyle, animationStyle]}
                 onLayout={(e) => {
-                    const { height, width } = e.nativeEvent.layout;
+                    const {height, width} = e.nativeEvent.layout;
                     if (height === wrapperMeasuredHeightAnimated.get()) {
                         return;
                     }
