diff --git a/src/components/Composer/implementation/index.native.tsx b/src/components/Composer/implementation/index.native.tsx index d5f72f7088b2..cea339de07e2 100644 --- a/src/components/Composer/implementation/index.native.tsx +++ b/src/components/Composer/implementation/index.native.tsx @@ -57,6 +57,25 @@ function Composer( inputCallbackRef(autoFocus ? textInput.current : null); }, [autoFocus, inputCallbackRef, autoFocusInputRef]); + useEffect(() => { + if (!textInput.current || !textInput.current.setSelection || !selection || isComposerFullSize) { + return; + } + + // We need the delay for setSelection to properly work for IOS in bridgeless mode due to a react native + // internal bug of dispatching the event before the component is ready for it. + // (see https://github.com/Expensify/App/pull/50520#discussion_r1861960311 for more context) + const timeoutID = setTimeout(() => { + // We are setting selection twice to trigger a scroll to the cursor on toggling to smaller composer size. + textInput.current?.setSelection((selection.start || 1) - 1, selection.start); + textInput.current?.setSelection(selection.start, selection.start); + }, 0); + + return () => clearTimeout(timeoutID); + + // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps + }, [isComposerFullSize]); + /** * Set the TextInput Ref * @param {Element} el diff --git a/src/components/Composer/implementation/index.tsx b/src/components/Composer/implementation/index.tsx index e71ade65e66d..98ac9e00a98a 100755 --- a/src/components/Composer/implementation/index.tsx +++ b/src/components/Composer/implementation/index.tsx @@ -75,6 +75,7 @@ function Composer( const [isRendered, setIsRendered] = useState(false); const isScrollBarVisible = useIsScrollBarVisible(textInput, value ?? ''); const [prevScroll, setPrevScroll] = useState(); + const [prevHeight, setPrevHeight] = useState(); const isReportFlatListScrolling = useRef(false); useEffect(() => { @@ -243,11 +244,11 @@ function Composer( }, []); useEffect(() => { - if (!textInput.current || prevScroll === undefined) { + if (!textInput.current || prevScroll === undefined || prevHeight === undefined) { return; } // eslint-disable-next-line react-compiler/react-compiler - textInput.current.scrollTop = prevScroll; + textInput.current.scrollTop = prevScroll + prevHeight - textInput.current.clientHeight; // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps }, [isComposerFullSize]); @@ -353,6 +354,7 @@ function Composer( {...props} onSelectionChange={addCursorPositionToSelectionChange} onContentSizeChange={(e) => { + setPrevHeight(e.nativeEvent.contentSize.height); setHasMultipleLines(e.nativeEvent.contentSize.height > variables.componentSizeLarge); }} disabled={isDisabled}