diff --git a/src/libs/ReportActionComposeFocusManager.ts b/src/libs/ReportActionComposeFocusManager.ts index cf97524fb3a3f..4d6a2b3398093 100644 --- a/src/libs/ReportActionComposeFocusManager.ts +++ b/src/libs/ReportActionComposeFocusManager.ts @@ -9,7 +9,10 @@ import navigationRef from './Navigation/navigationRef'; type FocusCallback = (shouldFocusForNonBlurInputOnTapOutside?: boolean) => void; const composerRef: MutableRefObject = React.createRef(); -const editComposerRef = React.createRef(); + +// There are two types of composer: general composer (edit composer) and main composer. +// The general composer callback will take priority if it exists. +const editComposerRef: MutableRefObject = React.createRef(); // There are two types of focus callbacks: priority and general // Priority callback would take priority if it existed let priorityFocusCallback: FocusCallback | null = null; @@ -58,6 +61,7 @@ function focus(shouldFocusForNonBlurInputOnTapOutside?: boolean) { */ function clear(isPriorityCallback = false) { if (isPriorityCallback) { + editComposerRef.current = null; priorityFocusCallback = null; } else { focusCallback = null; @@ -78,6 +82,14 @@ function isEditFocused(): boolean { return !!editComposerRef.current?.isFocused(); } +/** + * Utility function to blur both main composer and edit composer. + */ +function blurAll(): void { + composerRef.current?.blur(); + editComposerRef.current?.blur(); +} + export default { composerRef, onComposerFocus, @@ -86,4 +98,5 @@ export default { isFocused, editComposerRef, isEditFocused, + blurAll, }; diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index 0d2efbfded2cb..91a3d5b7d1f68 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -48,6 +48,7 @@ import Navigation from '@libs/Navigation/Navigation'; import Permissions from '@libs/Permissions'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; import * as PolicyUtils from '@libs/PolicyUtils'; +import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManager'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import SelectionScraper from '@libs/SelectionScraper'; @@ -335,6 +336,7 @@ function ReportActionItem({ return; } + ReportActionComposeFocusManager.blurAll(); setIsContextMenuActive(true); const selection = SelectionScraper.getCurrentSelection(); ReportActionContextMenu.showContextMenu( diff --git a/src/pages/home/report/ReportActionItemMessageEdit.tsx b/src/pages/home/report/ReportActionItemMessageEdit.tsx index d1eb78bcc00ee..dffac2407c63d 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.tsx +++ b/src/pages/home/report/ReportActionItemMessageEdit.tsx @@ -167,6 +167,22 @@ function ReportActionItemMessageEdit( }; }, []); + useEffect( + // Remove focus callback on unmount to avoid stale callbacks + () => { + if (textInputRef.current) { + ReportActionComposeFocusManager.editComposerRef.current = textInputRef.current; + } + return () => { + if (ReportActionComposeFocusManager.editComposerRef.current !== textInputRef.current) { + return; + } + ReportActionComposeFocusManager.clear(true); + }; + }, + [], + ); + // We consider the report action active if it's focused, its emoji picker is open or its context menu is open const isActive = useCallback( () => isFocusedRef.current || EmojiPickerAction.isActive(action.reportActionID) || ReportActionContextMenu.isActiveReportAction(action.reportActionID), @@ -188,14 +204,6 @@ function ReportActionItemMessageEdit( }, true); }, [focus]); - useEffect( - // Remove focus callback on unmount to avoid stale callbacks - () => () => { - ReportActionComposeFocusManager.clear(true); - }, - [], - ); - useEffect( () => { if (isInitialMount.current) { @@ -516,6 +524,9 @@ function ReportActionItemMessageEdit( style={[styles.textInputCompose, styles.flex1, styles.bgTransparent]} onFocus={() => { setIsFocused(true); + if (textInputRef.current) { + ReportActionComposeFocusManager.editComposerRef.current = textInputRef.current; + } InteractionManager.runAfterInteractions(() => { requestAnimationFrame(() => { reportScrollManager.scrollToIndex(index, true);