From c7e3f5a133d9359e9c1074086fca073fcbd50e3c Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Wed, 9 Oct 2024 22:54:21 +0300 Subject: [PATCH 01/13] fix the bottom line of the composer on composer full size mode change --- src/components/Composer/index.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/components/Composer/index.tsx b/src/components/Composer/index.tsx index 15087193a593..8a899d4e3562 100755 --- a/src/components/Composer/index.tsx +++ b/src/components/Composer/index.tsx @@ -102,6 +102,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(() => { @@ -231,10 +232,18 @@ function Composer( } setPrevScroll(textInput.current.scrollTop); }, 100); + const debouncedSetPrevHeight = lodashDebounce(() => { + if (!textInput.current) { + return; + } + setPrevHeight(textInput.current.clientHeight); + }, 100); textInput.current.addEventListener('scroll', debouncedSetPrevScroll); + textInput.current.addEventListener('resize', debouncedSetPrevHeight); return () => { textInput.current?.removeEventListener('scroll', debouncedSetPrevScroll); + textInput.current?.removeEventListener('resize', debouncedSetPrevHeight); }; }, []); @@ -262,11 +271,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]); From 26926f016bba9f99ca73b511ef3983db6ed77e35 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Wed, 9 Oct 2024 23:03:30 +0300 Subject: [PATCH 02/13] change listener --- src/components/Composer/index.tsx | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/components/Composer/index.tsx b/src/components/Composer/index.tsx index 8a899d4e3562..56a0a06e9c30 100755 --- a/src/components/Composer/index.tsx +++ b/src/components/Composer/index.tsx @@ -231,19 +231,12 @@ function Composer( return; } setPrevScroll(textInput.current.scrollTop); - }, 100); - const debouncedSetPrevHeight = lodashDebounce(() => { - if (!textInput.current) { - return; - } setPrevHeight(textInput.current.clientHeight); }, 100); textInput.current.addEventListener('scroll', debouncedSetPrevScroll); - textInput.current.addEventListener('resize', debouncedSetPrevHeight); return () => { textInput.current?.removeEventListener('scroll', debouncedSetPrevScroll); - textInput.current?.removeEventListener('resize', debouncedSetPrevHeight); }; }, []); From 447dc037c2e6f26b82f305160e7bd005559b2a48 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Wed, 9 Oct 2024 23:22:39 +0300 Subject: [PATCH 03/13] set prevHeight to content size height --- src/components/Composer/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Composer/index.tsx b/src/components/Composer/index.tsx index 56a0a06e9c30..21708d85612b 100755 --- a/src/components/Composer/index.tsx +++ b/src/components/Composer/index.tsx @@ -231,7 +231,6 @@ function Composer( return; } setPrevScroll(textInput.current.scrollTop); - setPrevHeight(textInput.current.clientHeight); }, 100); textInput.current.addEventListener('scroll', debouncedSetPrevScroll); @@ -395,6 +394,7 @@ function Composer( {...props} onSelectionChange={addCursorPositionToSelectionChange} onContentSizeChange={(e) => { + setPrevHeight(e.nativeEvent.contentSize.height); setTextInputWidth(`${e.nativeEvent.contentSize.width}px`); updateIsFullComposerAvailable({maxLines, isComposerFullSize, isDisabled, setIsFullComposerAvailable}, e, styles); }} From ccb9ca5eca10055b51a4f084ba29e2e76d1a2f17 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Tue, 22 Oct 2024 16:02:17 +0300 Subject: [PATCH 04/13] resolve conflict --- src/components/Composer/implementation/index.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/Composer/implementation/index.tsx b/src/components/Composer/implementation/index.tsx index 4431007793cb..6c4a1a4c723c 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); updateIsFullComposerAvailable({maxLines, isComposerFullSize, isDisabled, setIsFullComposerAvailable}, e, styles); }} disabled={isDisabled} From dca3bcc040cf5545c1feabb88f63289ae65ce4e5 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Wed, 23 Oct 2024 18:47:15 +0300 Subject: [PATCH 05/13] scroll to the cursor on composer size change for native --- .../Composer/implementation/index.native.tsx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/components/Composer/implementation/index.native.tsx b/src/components/Composer/implementation/index.native.tsx index 9f237dd02424..905fa537ff55 100644 --- a/src/components/Composer/implementation/index.native.tsx +++ b/src/components/Composer/implementation/index.native.tsx @@ -59,6 +59,17 @@ function Composer( inputCallbackRef(autoFocus ? textInput.current : null); }, [autoFocus, inputCallbackRef, autoFocusInputRef]); + useEffect(() => { + if (!textInput.current || !selection) { + return; + } + + // We are setting selection twice to trigger a scroll to the cursor on change of composer size. + textInput.current?.setSelection((selection.start || 1) - 1, selection.start); + textInput.current?.setSelection(selection.start, selection.start); + // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps + }, [isComposerFullSize]); + /** * Set the TextInput Ref * @param {Element} el From 54402d18f585bfc1c34e61502c43d910d505e341 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Mon, 28 Oct 2024 18:40:39 +0300 Subject: [PATCH 06/13] comment out the set selection code --- .../Composer/implementation/index.native.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/components/Composer/implementation/index.native.tsx b/src/components/Composer/implementation/index.native.tsx index 905fa537ff55..23531ceafa83 100644 --- a/src/components/Composer/implementation/index.native.tsx +++ b/src/components/Composer/implementation/index.native.tsx @@ -59,16 +59,16 @@ function Composer( inputCallbackRef(autoFocus ? textInput.current : null); }, [autoFocus, inputCallbackRef, autoFocusInputRef]); - useEffect(() => { - if (!textInput.current || !selection) { - return; - } + // useEffect(() => { + // if (!textInput.current || !selection) { + // return; + // } - // We are setting selection twice to trigger a scroll to the cursor on change of composer size. - textInput.current?.setSelection((selection.start || 1) - 1, selection.start); - textInput.current?.setSelection(selection.start, selection.start); - // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps - }, [isComposerFullSize]); + // // We are setting selection twice to trigger a scroll to the cursor on change of composer size. + // textInput.current?.setSelection((selection.start || 1) - 1, selection.start); + // textInput.current?.setSelection(selection.start, selection.start); + // // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps + // }, [isComposerFullSize]); /** * Set the TextInput Ref From 4e65339fec300f16e3ff124bc5c4d1c88b7095d7 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Mon, 28 Oct 2024 23:33:16 +0300 Subject: [PATCH 07/13] revert --- .../Composer/implementation/index.native.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/components/Composer/implementation/index.native.tsx b/src/components/Composer/implementation/index.native.tsx index 23531ceafa83..905fa537ff55 100644 --- a/src/components/Composer/implementation/index.native.tsx +++ b/src/components/Composer/implementation/index.native.tsx @@ -59,16 +59,16 @@ function Composer( inputCallbackRef(autoFocus ? textInput.current : null); }, [autoFocus, inputCallbackRef, autoFocusInputRef]); - // useEffect(() => { - // if (!textInput.current || !selection) { - // return; - // } + useEffect(() => { + if (!textInput.current || !selection) { + return; + } - // // We are setting selection twice to trigger a scroll to the cursor on change of composer size. - // textInput.current?.setSelection((selection.start || 1) - 1, selection.start); - // textInput.current?.setSelection(selection.start, selection.start); - // // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps - // }, [isComposerFullSize]); + // We are setting selection twice to trigger a scroll to the cursor on change of composer size. + textInput.current?.setSelection((selection.start || 1) - 1, selection.start); + textInput.current?.setSelection(selection.start, selection.start); + // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps + }, [isComposerFullSize]); /** * Set the TextInput Ref From aa8156ddbb3b807b3226a693289a6df4ad5fa310 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Mon, 28 Oct 2024 23:36:09 +0300 Subject: [PATCH 08/13] only scroll to cursor on changing to composer to small size --- src/components/Composer/implementation/index.native.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Composer/implementation/index.native.tsx b/src/components/Composer/implementation/index.native.tsx index 905fa537ff55..74c96555b644 100644 --- a/src/components/Composer/implementation/index.native.tsx +++ b/src/components/Composer/implementation/index.native.tsx @@ -60,11 +60,11 @@ function Composer( }, [autoFocus, inputCallbackRef, autoFocusInputRef]); useEffect(() => { - if (!textInput.current || !selection) { + if (!textInput.current || !selection || isComposerFullSize) { return; } - // We are setting selection twice to trigger a scroll to the cursor on change of composer size. + // 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); // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps From 913563b841946fbbe5bedee861233f19ab9484dc Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Tue, 29 Oct 2024 00:30:19 +0300 Subject: [PATCH 09/13] fix tests --- src/components/Composer/implementation/index.native.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Composer/implementation/index.native.tsx b/src/components/Composer/implementation/index.native.tsx index 74c96555b644..9f136effa857 100644 --- a/src/components/Composer/implementation/index.native.tsx +++ b/src/components/Composer/implementation/index.native.tsx @@ -60,7 +60,7 @@ function Composer( }, [autoFocus, inputCallbackRef, autoFocusInputRef]); useEffect(() => { - if (!textInput.current || !selection || isComposerFullSize) { + if (!textInput.current || !textInput.current.setSelection || !selection || isComposerFullSize) { return; } From d8076c19009b08cfaf29cdeae29349bd873d9a6f Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Fri, 1 Nov 2024 23:00:47 +0300 Subject: [PATCH 10/13] applied small delay to setSelection --- src/components/Composer/implementation/index.native.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/Composer/implementation/index.native.tsx b/src/components/Composer/implementation/index.native.tsx index 9f136effa857..e5c2b309ad82 100644 --- a/src/components/Composer/implementation/index.native.tsx +++ b/src/components/Composer/implementation/index.native.tsx @@ -65,8 +65,13 @@ function Composer( } // 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); + const timeoutID = setTimeout(() => { + textInput.current?.setSelection((selection.start || 1) - 1, selection.start); + textInput.current?.setSelection(selection.start, selection.start); + }, 100); + + return () => clearTimeout(timeoutID); + // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps }, [isComposerFullSize]); From 295079ffbe9de26548ec2ed84a6e78ccf5082b82 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Fri, 1 Nov 2024 23:02:46 +0300 Subject: [PATCH 11/13] reduced the delay --- src/components/Composer/implementation/index.native.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Composer/implementation/index.native.tsx b/src/components/Composer/implementation/index.native.tsx index e5c2b309ad82..0eee0be257d4 100644 --- a/src/components/Composer/implementation/index.native.tsx +++ b/src/components/Composer/implementation/index.native.tsx @@ -68,7 +68,7 @@ function Composer( const timeoutID = setTimeout(() => { textInput.current?.setSelection((selection.start || 1) - 1, selection.start); textInput.current?.setSelection(selection.start, selection.start); - }, 100); + }, 0); return () => clearTimeout(timeoutID); From d80be2ac924a7d2d314dd0a3d5fee31ffc180839 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Sat, 30 Nov 2024 00:07:14 +0300 Subject: [PATCH 12/13] added comment --- src/components/Composer/implementation/index.native.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/Composer/implementation/index.native.tsx b/src/components/Composer/implementation/index.native.tsx index 3a84e01d70c5..96527b105853 100644 --- a/src/components/Composer/implementation/index.native.tsx +++ b/src/components/Composer/implementation/index.native.tsx @@ -62,8 +62,9 @@ function Composer( return; } - // We are setting selection twice to trigger a scroll to the cursor on toggling to smaller composer size. + // We need the delay for setSelection to properly work for IOS. 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); From 6542b02b8b2a01c14ef892bd277df5f42a048c78 Mon Sep 17 00:00:00 2001 From: FitseTLT Date: Wed, 4 Dec 2024 16:36:28 +0300 Subject: [PATCH 13/13] updated comment --- src/components/Composer/implementation/index.native.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/Composer/implementation/index.native.tsx b/src/components/Composer/implementation/index.native.tsx index 96527b105853..cea339de07e2 100644 --- a/src/components/Composer/implementation/index.native.tsx +++ b/src/components/Composer/implementation/index.native.tsx @@ -62,7 +62,9 @@ function Composer( return; } - // We need the delay for setSelection to properly work for IOS. + // 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);