diff --git a/app/components/emoji_category_bar/index.tsx b/app/components/emoji_category_bar/index.tsx index 1c398721e..6f1184ae8 100644 --- a/app/components/emoji_category_bar/index.tsx +++ b/app/components/emoji_category_bar/index.tsx @@ -9,6 +9,7 @@ import TouchableWithFeedback from '@components/touchable_with_feedback'; import {useKeyboardAnimationContext} from '@context/keyboard_animation'; import {useTheme} from '@context/theme'; import {selectEmojiCategoryBarSection, useEmojiCategoryBar} from '@hooks/emoji_category_bar'; +import {useFocusAfterEmojiDismiss} from '@hooks/useFocusAfterEmojiDismiss'; import {usePreventDoubleTap} from '@hooks/utils'; import {deleteLastGrapheme} from '@utils/grapheme'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; @@ -61,11 +62,14 @@ const EmojiCategoryBar = ({onSelect}: Props) => { const keyboardContext = useKeyboardAnimationContext(); const { focusInput, + inputRef, updateValue, updateCursorPosition, cursorPositionRef, } = keyboardContext; + const {focus: focusWithEmojiDismiss} = useFocusAfterEmojiDismiss(inputRef, focusInput); + // Only show keyboard/delete buttons if we're in input accessory view mode // Check if updateValue is available (not null) to determine if we're in input accessory context const showActionButtons = updateValue !== null; @@ -80,8 +84,8 @@ const EmojiCategoryBar = ({onSelect}: Props) => { }, [onSelect]); const handleKeyboardPress = usePreventDoubleTap(useCallback(() => { - focusInput(); - }, [focusInput])); + focusWithEmojiDismiss(); + }, [focusWithEmojiDismiss])); const deleteCharFromCurrentCursorPosition = useCallback(() => { if (!updateValue || !updateCursorPosition || !cursorPositionRef) { diff --git a/app/hooks/useFocusAfterEmojiDismiss.ts b/app/hooks/useFocusAfterEmojiDismiss.ts index dde368275..1c7a0cb29 100644 --- a/app/hooks/useFocusAfterEmojiDismiss.ts +++ b/app/hooks/useFocusAfterEmojiDismiss.ts @@ -45,13 +45,16 @@ export const useFocusAfterEmojiDismiss = ( inputRef.current?.blur(); - const handleDelayedFocus = () => { - focusInput(); - setIsManuallyFocusingAfterEmojiDismiss(false); - focusTimeoutRef.current = null; - }; + // Use requestAnimationFrame to ensure state updates have been applied + requestAnimationFrame(() => { + const handleDelayedFocus = () => { + focusInput(); + setIsManuallyFocusingAfterEmojiDismiss(false); + focusTimeoutRef.current = null; + }; - focusTimeoutRef.current = setTimeout(handleDelayedFocus, 200); + focusTimeoutRef.current = setTimeout(handleDelayedFocus, 200); + }); return () => { if (focusTimeoutRef.current) { @@ -80,6 +83,20 @@ export const useFocusAfterEmojiDismiss = ( setIsEmojiSearchFocused(false); setShowInputAccessoryView(false); + + if (focusTimeoutRef.current) { + clearTimeout(focusTimeoutRef.current); + } + + inputRef.current?.blur(); + + // Schedule focus after emoji picker closes + focusTimeoutRef.current = setTimeout(() => { + focusInput(); + setIsManuallyFocusingAfterEmojiDismiss(false); + isDismissingEmojiPicker.current = false; + focusTimeoutRef.current = null; + }, 200); } else { focusInput(); } @@ -91,6 +108,7 @@ export const useFocusAfterEmojiDismiss = ( keyboardTranslateY, isTransitioningFromCustomView, setIsEmojiSearchFocused, + inputRef, focusInput, ]);