@@ -4,6 +4,8 @@ import React, {useCallback, useEffect, useImperativeHandle, useRef, useState} fr
44import type { EmitterSubscription , GestureResponderEvent , NativeTouchEvent , View } from 'react-native' ;
55import { DeviceEventEmitter , Dimensions , InteractionManager } from 'react-native' ;
66import type { OnyxEntry } from 'react-native-onyx' ;
7+ import { cancelAnimation , useSharedValue , withTiming } from 'react-native-reanimated' ;
8+ import { scheduleOnRN } from 'react-native-worklets' ;
79import { Actions , useActionSheetAwareScrollViewActions } from '@components/ActionSheetAwareScrollView' ;
810import ConfirmModal from '@components/ConfirmModal' ;
911import PopoverWithMeasuredContent from '@components/PopoverWithMeasuredContent' ;
@@ -77,6 +79,8 @@ function PopoverReportActionContextMenu({ref}: PopoverReportActionContextMenuPro
7779 const { email, accountID : currentUserAccountID } = useCurrentUserPersonalDetails ( ) ;
7880
7981 const [ isPopoverVisible , setIsPopoverVisible ] = useState ( false ) ;
82+ // UI-thread timer driving the delayed hide. https://github.com/Expensify/App/issues/89069
83+ const hideDelayProgress = useSharedValue ( 0 ) ;
8084 const [ isDeleteCommentConfirmModalVisible , setIsDeleteCommentConfirmModalVisible ] = useState ( false ) ;
8185 const [ shouldSetModalVisibilityForDeleteConfirmation , setShouldSetModalVisibilityForDeleteConfirmation ] = useState ( true ) ;
8286
@@ -183,6 +187,7 @@ function PopoverReportActionContextMenu({ref}: PopoverReportActionContextMenuPro
183187 * @param isUnreadChat - Flag to check if the chat is unread in the LHN. Used for the Mark as Read/Unread action
184188 */
185189 const showContextMenu : ReportActionContextMenu [ 'showContextMenu' ] = ( showContextMenuParams ) => {
190+ cancelAnimation ( hideDelayProgress ) ;
186191 const {
187192 type,
188193 event,
@@ -295,13 +300,7 @@ function PopoverReportActionContextMenu({ref}: PopoverReportActionContextMenuPro
295300 * Hide the ReportActionContextMenu modal popover.
296301 * @param onHideActionCallback Callback to be called after popover is completely hidden
297302 */
298- const hideContextMenu : ReportActionContextMenu [ 'hideContextMenu' ] = ( hideContextMenuParams ) => {
299- const { callbacks = { } } = hideContextMenuParams ?? { } ;
300-
301- if ( typeof callbacks . onHide === 'function' ) {
302- onPopoverHideActionCallback . current = callbacks . onHide ;
303- }
304-
303+ const performHide = ( ) => {
305304 selectionRef . current = '' ;
306305 reportActionDraftMessageRef . current = undefined ;
307306 setIsPopoverVisible ( false ) ;
@@ -315,6 +314,33 @@ function PopoverReportActionContextMenu({ref}: PopoverReportActionContextMenuPro
315314 } ) ;
316315 } ;
317316
317+ const hideContextMenu : ReportActionContextMenu [ 'hideContextMenu' ] = ( hideContextMenuParams ) => {
318+ const { callbacks = { } , hideDelayMs} = hideContextMenuParams ?? { } ;
319+
320+ if ( typeof callbacks . onHide === 'function' ) {
321+ onPopoverHideActionCallback . current = callbacks . onHide ;
322+ }
323+
324+ cancelAnimation ( hideDelayProgress ) ;
325+
326+ if ( ! hideDelayMs || hideDelayMs <= 0 ) {
327+ performHide ( ) ;
328+ return ;
329+ }
330+
331+ // UI-thread delayed hide. https://github.com/Expensify/App/issues/89069
332+ hideDelayProgress . set ( 0 ) ;
333+ hideDelayProgress . set (
334+ withTiming ( 1 , { duration : hideDelayMs } , ( finished ) => {
335+ 'worklet' ;
336+
337+ if ( finished ) {
338+ scheduleOnRN ( performHide ) ;
339+ }
340+ } ) ,
341+ ) ;
342+ } ;
343+
318344 const transactionIDs : string [ ] = [ ] ;
319345 if ( isMoneyRequestAction ( reportActionRef . current ) ) {
320346 const originalMessage = getOriginalMessage ( reportActionRef . current ) ;
0 commit comments