diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx index 3c062deaadbd3..f2b0794b3b1a8 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx @@ -3,7 +3,7 @@ import lodashDebounce from 'lodash/debounce'; import type {ForwardedRef, RefObject} from 'react'; import React, {memo, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react'; import type {BlurEvent, LayoutChangeEvent, MeasureInWindowOnSuccessCallback, TextInput, TextInputContentSizeChangeEvent, TextInputKeyPressEvent, TextInputScrollEvent} from 'react-native'; -import {DeviceEventEmitter, InteractionManager, NativeModules, StyleSheet, View} from 'react-native'; +import {DeviceEventEmitter, NativeModules, StyleSheet, View} from 'react-native'; import {useFocusedInputHandler} from 'react-native-keyboard-controller'; import type {OnyxEntry} from 'react-native-onyx'; import {useAnimatedRef, useSharedValue} from 'react-native-reanimated'; @@ -27,7 +27,6 @@ import {canSkipTriggerHotkeys, findCommonSuffixLength, insertText, insertWhiteSp import convertToLTRForComposer from '@libs/convertToLTRForComposer'; import {containsOnlyEmojis, extractEmojis, getAddedEmojis, getPreferredSkinToneIndex, replaceAndExtractEmojis} from '@libs/EmojiUtils'; import focusComposerWithDelay from '@libs/focusComposerWithDelay'; -import getPlatform from '@libs/getPlatform'; import {addKeyDownPressListener, removeKeyDownPressListener} from '@libs/KeyboardShortcut/KeyDownPressListener'; import {detectAndRewritePaste} from '@libs/MarkdownLinkHelpers'; import Parser from '@libs/Parser'; @@ -53,11 +52,6 @@ import type ChildrenProps from '@src/types/utils/ChildrenProps'; // eslint-disable-next-line no-restricted-imports import findNodeHandle from '@src/utils/findNodeHandle'; -type SyncSelection = { - position: number; - value: string; -}; - type NewlyAddedChars = {startIndex: number; endIndex: number; diff: string}; type ComposerWithSuggestionsProps = Partial & { @@ -160,8 +154,6 @@ type ComposerRef = { const {RNTextInputReset} = NativeModules; -const isIOSNative = getPlatform() === CONST.PLATFORM.IOS; - /** * Broadcast that the user is typing. Debounced to limit how often we publish client events. */ @@ -269,9 +261,9 @@ function ComposerWithSuggestions({ const [composerHeight, setComposerHeight] = useState(0); - const textInputRef = useRef(null); + const [suggestionPosition, setSuggestionPosition] = useState(null); - const syncSelectionWithOnChangeTextRef = useRef(null); + const textInputRef = useRef(null); // The ref to check whether the comment saving is in progress const isCommentPendingSaved = useRef(false); @@ -415,10 +407,6 @@ function ComposerWithSuggestions({ if (commentValue !== newComment) { const position = Math.max((selection.end ?? 0) + (newComment.length - commentRef.current.length), cursorPosition ?? 0); - if (commentWithSpaceInserted !== newComment && isIOSNative) { - syncSelectionWithOnChangeTextRef.current = {position, value: newComment}; - } - setSelection((prevSelection) => ({ start: position, end: position, @@ -524,25 +512,18 @@ function ComposerWithSuggestions({ [shouldUseNarrowLayout, isKeyboardShown, suggestionsRef, selection.start, includeChronos, handleSendMessage, lastReportAction, reportID, updateComment, selection.end], ); - const onChangeText = useCallback( - (commentValue: string) => { - updateComment(commentValue, true); + useEffect(() => { + if (suggestionPosition === null) { + return; + } - if (isIOSNative && syncSelectionWithOnChangeTextRef.current) { - const positionSnapshot = syncSelectionWithOnChangeTextRef.current.position; - syncSelectionWithOnChangeTextRef.current = null; + textInputRef.current?.setSelection?.(suggestionPosition, suggestionPosition); + }, [suggestionPosition]); - // ensure that selection is set imperatively after all state changes are effective - // eslint-disable-next-line @typescript-eslint/no-deprecated - InteractionManager.runAfterInteractions(() => { - // note: this implementation is only available on non-web RN, thus the wrapping - // 'if' block contains a redundant (since the ref is only used on iOS) platform check - textInputRef.current?.setSelection(positionSnapshot, positionSnapshot); - }); - } - }, - [updateComment], - ); + const onSuggestionSelected = useCallback((suggestion: TextSelection) => { + setSelection(suggestion); + setSuggestionPosition(suggestion.end ?? 0); + }, []); const onSelectionChange = useCallback( (e: CustomSelectionChangeEvent) => { @@ -827,7 +808,7 @@ function ComposerWithSuggestions({ ref={setTextInputRef} placeholder={inputPlaceholder} placeholderTextColor={theme.placeholderText} - onChangeText={onChangeText} + onChangeText={updateComment} onKeyPress={handleKeyPress} textAlignVertical="top" style={[styles.textInputCompose, isComposerFullSize ? styles.textInputFullCompose : styles.textInputCollapseCompose]} @@ -865,7 +846,7 @@ function ComposerWithSuggestions({ // Input value={value} selection={selection} - setSelection={setSelection} + setSelection={onSuggestionSelected} resetKeyboardInput={resetKeyboardInput} />