diff --git a/src/libs/focusComposerWithDelay.ts b/src/libs/focusComposerWithDelay.ts index 19f1050d24bd..42274314e3a7 100644 --- a/src/libs/focusComposerWithDelay.ts +++ b/src/libs/focusComposerWithDelay.ts @@ -1,17 +1,23 @@ -import {TextInput} from 'react-native'; +import {Platform, TextInput} from 'react-native'; +import CONST from '@src/CONST'; import * as EmojiPickerAction from './actions/EmojiPickerAction'; import ComposerFocusManager from './ComposerFocusManager'; +type Selection = { + start: number; + end: number; +}; + type FocusComposerWithDelay = (shouldDelay?: boolean) => void; /** * Create a function that focuses the composer. */ -function focusComposerWithDelay(textInput: TextInput | null): FocusComposerWithDelay { +function focusComposerWithDelay(textInput: TextInput | HTMLTextAreaElement | null): FocusComposerWithDelay { /** * Focus the text input * @param [shouldDelay] Impose delay before focusing the text input */ - return (shouldDelay = false) => { + return (shouldDelay = false, forceSetSelection?: Selection) => { // There could be other animations running while we trigger manual focus. // This prevents focus from making those animations janky. if (!textInput || EmojiPickerAction.isEmojiPickerVisible()) { @@ -20,6 +26,13 @@ function focusComposerWithDelay(textInput: TextInput | null): FocusComposerWithD if (!shouldDelay) { textInput.focus(); + if (forceSetSelection) { + if (Platform.OS === CONST.PLATFORM.WEB) { + (textInput as HTMLTextAreaElement).setSelectionRange(forceSetSelection.start, forceSetSelection.end); + } else { + (textInput as TextInput).setSelection(forceSetSelection.start, forceSetSelection.end); + } + } return; } ComposerFocusManager.isReadyToFocus().then(() => { @@ -27,6 +40,13 @@ function focusComposerWithDelay(textInput: TextInput | null): FocusComposerWithD return; } textInput.focus(); + if (forceSetSelection) { + if (Platform.OS === CONST.PLATFORM.WEB) { + (textInput as HTMLTextAreaElement).setSelectionRange(forceSetSelection.start, forceSetSelection.end); + } else { + (textInput as TextInput).setSelection(forceSetSelection.start, forceSetSelection.end); + } + } }); }; } diff --git a/src/pages/home/report/ReportActionItemMessageEdit.js b/src/pages/home/report/ReportActionItemMessageEdit.js index c8ea0d5e3514..d6aaba079765 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.js +++ b/src/pages/home/report/ReportActionItemMessageEdit.js @@ -78,6 +78,7 @@ const emojiButtonID = 'emojiButton'; const messageEditInput = 'messageEditInput'; const isMobileSafari = Browser.isMobileSafari(); +const isMobileChrome = Browser.isMobileChrome(); function ReportActionItemMessageEdit(props) { const theme = useTheme(); @@ -87,6 +88,8 @@ function ReportActionItemMessageEdit(props) { const {isKeyboardShown} = useKeyboardState(); const {isSmallScreenWidth} = useWindowDimensions(); + const emojiPickerSelectionRef = useRef(undefined); + const getInitialDraft = () => { if (props.draftMessage === props.action.message[0].html) { // We only convert the report action message to markdown if the draft message is unchanged. @@ -335,10 +338,18 @@ function ReportActionItemMessageEdit(props) { * @param {String} emoji */ const addEmojiToTextBox = (emoji) => { - setSelection((prevSelection) => ({ - start: prevSelection.start + emoji.length + CONST.SPACE_LENGTH, - end: prevSelection.start + emoji.length + CONST.SPACE_LENGTH, - })); + const newSelection = { + start: selection.start + emoji.length + CONST.SPACE_LENGTH, + end: selection.start + emoji.length + CONST.SPACE_LENGTH, + }; + setSelection(newSelection); + + if (isMobileChrome) { + // immediately set the selection again on Chrome mobile after focusing the + // input which seems to change the cursor position for a brief moment + emojiPickerSelectionRef.current = newSelection; + } + updateDraft(ComposerUtils.insertText(draft, selection, `${emoji} `)); }; @@ -440,7 +451,12 @@ function ReportActionItemMessageEdit(props) { focus(true)} + onModalHide={() => { + const emojiPickerSelection = emojiPickerSelectionRef.current ? {...emojiPickerSelectionRef.current} : undefined; + emojiPickerSelectionRef.current = undefined; + + focus(true, emojiPickerSelection); + }} onEmojiSelected={addEmojiToTextBox} id={emojiButtonID} emojiPickerID={props.action.reportActionID}