From 6a4d1f298d4f2c20ff96d91a9af368c8e417a3ef Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Fri, 28 Jun 2024 16:36:43 +0200 Subject: [PATCH 01/28] update const --- src/CONST.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CONST.ts b/src/CONST.ts index e71ad55a452c..af75e2886eab 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1233,7 +1233,7 @@ const CONST = { MAX_AMOUNT_OF_SUGGESTIONS: 20, MAX_AMOUNT_OF_VISIBLE_SUGGESTIONS_IN_CONTAINER: 5, HERE_TEXT: '@here', - SUGGESTION_BOX_MAX_SAFE_DISTANCE: 38, + SUGGESTION_BOX_MAX_SAFE_DISTANCE: 64, BIG_SCREEN_SUGGESTION_WIDTH: 300, }, COMPOSER_MAX_HEIGHT: 125, From 8987fd1d45182765ed72f00e51f5383dd68aa657 Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Fri, 28 Jun 2024 16:37:04 +0200 Subject: [PATCH 02/28] fix positioning --- src/components/AutoCompleteSuggestions/index.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/AutoCompleteSuggestions/index.tsx b/src/components/AutoCompleteSuggestions/index.tsx index 8634d6dd0ca0..84947ead9033 100644 --- a/src/components/AutoCompleteSuggestions/index.tsx +++ b/src/components/AutoCompleteSuggestions/index.tsx @@ -83,8 +83,8 @@ function AutoCompleteSuggestions({measureParentContainerAndReportCu const contentMaxHeight = measureHeightOfSuggestionRows(suggestionsLength, true); const contentMinHeight = measureHeightOfSuggestionRows(suggestionsLength, false); - const isEnoughSpaceAboveForBig = windowHeight - bottomValue - contentMaxHeight > CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_BOX_MAX_SAFE_DISTANCE; - const isEnoughSpaceAboveForSmall = windowHeight - bottomValue - contentMinHeight > CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_BOX_MAX_SAFE_DISTANCE; + const isEnoughSpaceAboveForBig = windowHeight - (bottomValue + keyboardHeight) - contentMaxHeight > CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_BOX_MAX_SAFE_DISTANCE; + const isEnoughSpaceAboveForSmall = windowHeight - (bottomValue + keyboardHeight) - contentMinHeight > CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_BOX_MAX_SAFE_DISTANCE; const newLeftValue = isSmallScreenWidth ? x : leftValueForBigScreen; // If the suggested word is longer than 150 (approximately half the width of the suggestion popup), then adjust a new position of popup @@ -106,7 +106,7 @@ function AutoCompleteSuggestions({measureParentContainerAndReportCu } else { // calculation for big suggestion box below the cursor measuredHeight = measureHeightOfSuggestionRows(suggestionsLength, true); - bottomValue = windowHeight - y - cursorCoordinates.y + scrollValue - measuredHeight - CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_ROW_HEIGHT; + bottomValue = windowHeight - y - cursorCoordinates.y + scrollValue - measuredHeight - CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_ROW_HEIGHT - keyboardHeight; } setSuggestionHeight(measuredHeight); setContainerState({ From cbb8243caf2438979b1186de5c1bf22957713068 Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Fri, 28 Jun 2024 18:27:03 +0200 Subject: [PATCH 03/28] types --- src/libs/focusComposerWithDelay/types.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libs/focusComposerWithDelay/types.ts b/src/libs/focusComposerWithDelay/types.ts index 4cd2f785f2bc..97a1298e8c7a 100644 --- a/src/libs/focusComposerWithDelay/types.ts +++ b/src/libs/focusComposerWithDelay/types.ts @@ -3,6 +3,8 @@ import type {TextInput} from 'react-native'; type Selection = { start: number; end: number; + positionX?: number; + positionY?: number; }; type FocusComposerWithDelay = (shouldDelay?: boolean, forcedSelectionRange?: Selection) => void; From 5fc92bfcf44bc1082356f7f678f454a91e29bc0f Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Mon, 1 Jul 2024 17:26:58 +0200 Subject: [PATCH 04/28] update SUGGESTION_BOX_MAX_SAFE_DISTANCE --- src/CONST.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CONST.ts b/src/CONST.ts index 5c473faf348d..c759148a0e0d 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1237,7 +1237,7 @@ const CONST = { MAX_AMOUNT_OF_SUGGESTIONS: 20, MAX_AMOUNT_OF_VISIBLE_SUGGESTIONS_IN_CONTAINER: 5, HERE_TEXT: '@here', - SUGGESTION_BOX_MAX_SAFE_DISTANCE: 64, + SUGGESTION_BOX_MAX_SAFE_DISTANCE: 48, BIG_SCREEN_SUGGESTION_WIDTH: 300, }, COMPOSER_MAX_HEIGHT: 125, From 9026d4b13d7b193aa03affff5c76ea64a8592d8d Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Mon, 1 Jul 2024 17:47:05 +0200 Subject: [PATCH 05/28] add runAfterInteractions --- .../home/report/ReportActionCompose/SuggestionEmoji.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx b/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx index 9b04fd7df4dc..444b9895abf5 100644 --- a/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx +++ b/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx @@ -1,5 +1,6 @@ import type {ForwardedRef, RefAttributes} from 'react'; import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState} from 'react'; +import {InteractionManager} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import type {Emoji} from '@assets/emojis/types'; import EmojiSuggestions from '@components/EmojiSuggestions'; @@ -181,7 +182,9 @@ function SuggestionEmoji( if (!isComposerFocused) { return; } - calculateEmojiSuggestion(selection.start, selection.end); + InteractionManager.runAfterInteractions(() => { + calculateEmojiSuggestion(selection.start, selection.end); + }); }, [selection, calculateEmojiSuggestion, isComposerFocused]); const setShouldBlockSuggestionCalc = useCallback( From b050267484b390edddce03b79a5ef2cedc347519 Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Mon, 1 Jul 2024 18:02:23 +0200 Subject: [PATCH 06/28] update ReportActionItemMessageEdit --- .../report/ReportActionItemMessageEdit.tsx | 107 +++++++++++++++++- 1 file changed, 103 insertions(+), 4 deletions(-) diff --git a/src/pages/home/report/ReportActionItemMessageEdit.tsx b/src/pages/home/report/ReportActionItemMessageEdit.tsx index d3c8ca3af8de..e8a248d4965b 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.tsx +++ b/src/pages/home/report/ReportActionItemMessageEdit.tsx @@ -1,11 +1,16 @@ import lodashDebounce from 'lodash/debounce'; import type {ForwardedRef} from 'react'; import React, {forwardRef, useCallback, useEffect, useMemo, useRef, useState} from 'react'; -import {InteractionManager, Keyboard, View} from 'react-native'; +import {findNodeHandle, InteractionManager, Keyboard, View} from 'react-native'; import type {NativeSyntheticEvent, TextInput, TextInputFocusEventData, TextInputKeyPressEventData} from 'react-native'; +import type {MeasureInWindowOnSuccessCallback, TextInputScrollEventData} from 'react-native'; +import {useFocusedInputHandler} from 'react-native-keyboard-controller'; import {useOnyx} from 'react-native-onyx'; +import {useSharedValue} from 'react-native-reanimated'; import type {Emoji} from '@assets/emojis/types'; +import type {MeasureParentContainerAndCursorCallback} from '@components/AutoCompleteSuggestions/types'; import Composer from '@components/Composer'; +import type {TextSelection} from '@components/Composer/types'; import EmojiPickerButton from '@components/EmojiPicker/EmojiPickerButton'; import ExceededCommentLength from '@components/ExceededCommentLength'; import Icon from '@components/Icon'; @@ -41,6 +46,10 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type * as OnyxTypes from '@src/types/onyx'; import * as ReportActionContextMenu from './ContextMenu/ReportActionContextMenu'; +import getCursorPosition from './ReportActionCompose/getCursorPosition'; +import getScrollPosition from './ReportActionCompose/getScrollPosition'; +import type {SuggestionsRef} from './ReportActionCompose/ReportActionCompose'; +import Suggestions from './ReportActionCompose/Suggestions'; import shouldUseEmojiPickerSelection from './shouldUseEmojiPickerSelection'; type ReportActionItemMessageEditProps = { @@ -80,11 +89,16 @@ function ReportActionItemMessageEdit( const theme = useTheme(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); + const containerRef = useRef(null); const reportScrollManager = useReportScrollManager(); const {translate, preferredLocale} = useLocalize(); const {isKeyboardShown} = useKeyboardState(); const {isSmallScreenWidth} = useWindowDimensions(); const prevDraftMessage = usePrevious(draftMessage); + const suggestionsRef = useRef(null); + const mobileInputScrollPosition = useRef(0); + const cursorPositionValue = useSharedValue({x: 0, y: 0}); + const tag = useSharedValue(-1); const emojisPresentBefore = useRef([]); const [draft, setDraft] = useState(() => { @@ -93,7 +107,7 @@ function ReportActionItemMessageEdit( } return draftMessage; }); - const [selection, setSelection] = useState({start: draft.length, end: draft.length}); + const [selection, setSelection] = useState({start: draft.length, end: draft.length, positionX: 0, positionY: 0}); const [isFocused, setIsFocused] = useState(false); const {hasExceededMaxCommentLength, validateCommentMaxLength} = useHandleExceedMaxCommentLength(); const [modal, setModal] = useState({ @@ -247,10 +261,12 @@ function ReportActionItemMessageEdit( setDraft(newDraft); if (newDraftInput !== newDraft) { - const position = Math.max(selection.end + (newDraft.length - draftRef.current.length), cursorPosition ?? 0); + const position = Math.max((selection?.end ?? 0) + (newDraft.length - draftRef.current.length), cursorPosition ?? 0); setSelection({ start: position, end: position, + positionX: 0, + positionY: 0, }); } @@ -317,6 +333,8 @@ function ReportActionItemMessageEdit( const newSelection = { start: selection.start + emoji.length + CONST.SPACE_LENGTH, end: selection.start + emoji.length + CONST.SPACE_LENGTH, + positionX: 0, + positionY: 0, }; setSelection(newSelection); @@ -350,6 +368,68 @@ function ReportActionItemMessageEdit( [deleteDraft, isKeyboardShown, isSmallScreenWidth, publishDraft], ); + const measureContainer = useCallback( + (callback: MeasureInWindowOnSuccessCallback) => { + if (!containerRef.current) { + return; + } + containerRef.current.measureInWindow(callback); + }, + // We added isComposerFullSize in dependencies so that when this value changes, we recalculate the position of the popup + // eslint-disable-next-line react-hooks/exhaustive-deps + [isFocused], + ); + + const measureParentContainerAndReportCursor = useCallback( + (callback: MeasureParentContainerAndCursorCallback) => { + const {scrollValue} = getScrollPosition({mobileInputScrollPosition, textInputRef}); + const {x: xPosition, y: yPosition} = getCursorPosition({positionOnMobile: cursorPositionValue.value, positionOnWeb: selection}); + measureContainer((x, y, width, height) => { + callback({ + x, + y, + width, + height, + scrollValue, + cursorCoordinates: {x: xPosition, y: yPosition}, + }); + }); + }, + [cursorPositionValue.value, measureContainer, selection], + ); + + const hideSuggestionMenu = useCallback( + (e: NativeSyntheticEvent) => { + mobileInputScrollPosition.current = e?.nativeEvent?.contentOffset?.y ?? 0; + + if (!suggestionsRef.current) { + return; + } + suggestionsRef.current.updateShouldShowSuggestionMenuToFalse(false); + }, + [suggestionsRef], + ); + + useEffect(() => { + tag.value = findNodeHandle(textInputRef.current) ?? -1; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + useFocusedInputHandler( + { + onSelectionChange: (event) => { + 'worklet'; + + if (event.target === tag.value) { + cursorPositionValue.value = { + x: event.selection.end.x, + y: event.selection.end.y, + }; + } + }, + }, + [], + ); + /** * Focus the composer text input */ @@ -361,7 +441,10 @@ function ReportActionItemMessageEdit( return ( <> - + setSelection(e.nativeEvent.selection)} isGroupPolicyReport={isGroupPolicyReport} + shouldCalculateCaretPosition + onScroll={hideSuggestionMenu} /> + + + Date: Tue, 2 Jul 2024 13:26:45 +0200 Subject: [PATCH 07/28] AutoCompleteSuggestions update --- src/components/AutoCompleteSuggestions/index.tsx | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/components/AutoCompleteSuggestions/index.tsx b/src/components/AutoCompleteSuggestions/index.tsx index 84947ead9033..f9fc4d0c94c2 100644 --- a/src/components/AutoCompleteSuggestions/index.tsx +++ b/src/components/AutoCompleteSuggestions/index.tsx @@ -48,7 +48,7 @@ function AutoCompleteSuggestions({measureParentContainerAndReportCu const StyleUtils = useStyleUtils(); const insets = useSafeAreaInsets(); const {keyboardHeight} = useKeyboardState(); - const {paddingBottom: bottomInset} = StyleUtils.getSafeAreaPadding(insets ?? undefined); + const {paddingBottom: bottomInset, paddingTop: topInset} = StyleUtils.getSafeAreaPadding(insets ?? undefined); useEffect(() => { const container = containerRef.current; @@ -77,15 +77,13 @@ function AutoCompleteSuggestions({measureParentContainerAndReportCu xCoordinatesOfCursor + CONST.AUTO_COMPLETE_SUGGESTER.BIG_SCREEN_SUGGESTION_WIDTH > windowWidth ? windowWidth - CONST.AUTO_COMPLETE_SUGGESTER.BIG_SCREEN_SUGGESTION_WIDTH : xCoordinatesOfCursor; - - let bottomValue = windowHeight - y - cursorCoordinates.y + scrollValue - (keyboardHeight || bottomInset); - const widthValue = isSmallScreenWidth ? width : CONST.AUTO_COMPLETE_SUGGESTER.BIG_SCREEN_SUGGESTION_WIDTH; - const contentMaxHeight = measureHeightOfSuggestionRows(suggestionsLength, true); const contentMinHeight = measureHeightOfSuggestionRows(suggestionsLength, false); - const isEnoughSpaceAboveForBig = windowHeight - (bottomValue + keyboardHeight) - contentMaxHeight > CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_BOX_MAX_SAFE_DISTANCE; - const isEnoughSpaceAboveForSmall = windowHeight - (bottomValue + keyboardHeight) - contentMinHeight > CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_BOX_MAX_SAFE_DISTANCE; + let bottomValue = windowHeight - (cursorCoordinates.y - scrollValue + y) - keyboardHeight; + const widthValue = isSmallScreenWidth ? width : CONST.AUTO_COMPLETE_SUGGESTER.BIG_SCREEN_SUGGESTION_WIDTH; + const isEnoughSpaceAboveForBig = y + (cursorCoordinates.y - scrollValue) > contentMaxHeight + topInset + CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_BOX_MAX_SAFE_DISTANCE; + const isEnoughSpaceAboveForSmall = y + (cursorCoordinates.y - scrollValue) > contentMinHeight + topInset + CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_BOX_MAX_SAFE_DISTANCE; const newLeftValue = isSmallScreenWidth ? x : leftValueForBigScreen; // If the suggested word is longer than 150 (approximately half the width of the suggestion popup), then adjust a new position of popup const isAdjustmentNeeded = Math.abs(prevLeftValue.current - leftValueForBigScreen) > 150; @@ -106,7 +104,7 @@ function AutoCompleteSuggestions({measureParentContainerAndReportCu } else { // calculation for big suggestion box below the cursor measuredHeight = measureHeightOfSuggestionRows(suggestionsLength, true); - bottomValue = windowHeight - y - cursorCoordinates.y + scrollValue - measuredHeight - CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_ROW_HEIGHT - keyboardHeight; + bottomValue = windowHeight - y - cursorCoordinates.y + scrollValue - measuredHeight - CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_ROW_HEIGHT - keyboardHeight - 0; } setSuggestionHeight(measuredHeight); setContainerState({ @@ -115,7 +113,7 @@ function AutoCompleteSuggestions({measureParentContainerAndReportCu width: widthValue, }); }); - }, [measureParentContainerAndReportCursor, windowHeight, windowWidth, keyboardHeight, isSmallScreenWidth, suggestionsLength, bottomInset]); + }, [measureParentContainerAndReportCursor, windowHeight, windowWidth, keyboardHeight, isSmallScreenWidth, suggestionsLength, bottomInset, topInset]); if (containerState.width === 0 && containerState.left === 0 && containerState.bottom === 0) { return null; From 376bbb1b77ba6760ac9710335c5bfa045df30680 Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Tue, 2 Jul 2024 13:27:00 +0200 Subject: [PATCH 08/28] change SUGGESTION_BOX_MAX_SAFE_DISTANCE --- src/CONST.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CONST.ts b/src/CONST.ts index 0aa42ef691f4..0f8b56dfae81 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1238,7 +1238,7 @@ const CONST = { MAX_AMOUNT_OF_SUGGESTIONS: 20, MAX_AMOUNT_OF_VISIBLE_SUGGESTIONS_IN_CONTAINER: 5, HERE_TEXT: '@here', - SUGGESTION_BOX_MAX_SAFE_DISTANCE: 48, + SUGGESTION_BOX_MAX_SAFE_DISTANCE: 10, BIG_SCREEN_SUGGESTION_WIDTH: 300, }, COMPOSER_MAX_HEIGHT: 125, From af3beca0173c2ee3237a1816dca81533f8e5423f Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Tue, 2 Jul 2024 13:27:22 +0200 Subject: [PATCH 09/28] add getBottomSuggestionPadding --- .../getBottomSuggestionPadding/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/AutoCompleteSuggestions/AutoCompleteSuggestionsPortal/getBottomSuggestionPadding/index.ts b/src/components/AutoCompleteSuggestions/AutoCompleteSuggestionsPortal/getBottomSuggestionPadding/index.ts index 3ad9bbe7b152..acdc643b6b70 100644 --- a/src/components/AutoCompleteSuggestions/AutoCompleteSuggestionsPortal/getBottomSuggestionPadding/index.ts +++ b/src/components/AutoCompleteSuggestions/AutoCompleteSuggestionsPortal/getBottomSuggestionPadding/index.ts @@ -1,5 +1,5 @@ function getBottomSuggestionPadding(): number { - return 0; + return 6; } export default getBottomSuggestionPadding; From fa0be2fe8b138b4ea95b712e758f23db5979136a Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Tue, 2 Jul 2024 13:28:02 +0200 Subject: [PATCH 10/28] calculateEmojiSuggestion --- src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx b/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx index 444b9895abf5..bc8883f371c1 100644 --- a/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx +++ b/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx @@ -179,9 +179,11 @@ function SuggestionEmoji( ); useEffect(() => { - if (!isComposerFocused) { + if (!isComposerFocused || (selection.start === 0 && selection.end === 0) || selection.start !== selection.end) { return; } + + // Avoid calling the function when keyboard animation running InteractionManager.runAfterInteractions(() => { calculateEmojiSuggestion(selection.start, selection.end); }); From 35448f333c5583dc0570fc087ec9777241286158 Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Tue, 2 Jul 2024 18:35:40 +0200 Subject: [PATCH 11/28] checkIfSuggestionVisible --- .../report/ReportActionCompose/ReportActionCompose.tsx | 1 + .../home/report/ReportActionCompose/SuggestionMention.tsx | 4 +++- src/pages/home/report/ReportActionCompose/Suggestions.tsx | 8 +++++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx index 8dcb5e199ba1..775e5bfa8e90 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx @@ -60,6 +60,7 @@ type SuggestionsRef = { updateShouldShowSuggestionMenuToFalse: (shouldShowSuggestionMenu?: boolean) => void; setShouldBlockSuggestionCalc: (shouldBlock: boolean) => void; getSuggestions: () => Mention[] | Emoji[]; + checkIfSuggestionVisible: () => boolean; }; type ReportActionComposeOnyxProps = { diff --git a/src/pages/home/report/ReportActionCompose/SuggestionMention.tsx b/src/pages/home/report/ReportActionCompose/SuggestionMention.tsx index 129c8c822d74..a103e8271044 100644 --- a/src/pages/home/report/ReportActionCompose/SuggestionMention.tsx +++ b/src/pages/home/report/ReportActionCompose/SuggestionMention.tsx @@ -408,6 +408,7 @@ function SuggestionMention( ); const getSuggestions = useCallback(() => suggestionValues.suggestedMentions, [suggestionValues]); + const checkIfSuggestionVisible = useCallback(() => isMentionSuggestionsMenuVisible, [isMentionSuggestionsMenuVisible]); useImperativeHandle( ref, @@ -417,8 +418,9 @@ function SuggestionMention( setShouldBlockSuggestionCalc, updateShouldShowSuggestionMenuToFalse, getSuggestions, + checkIfSuggestionVisible, }), - [resetSuggestions, setShouldBlockSuggestionCalc, triggerHotkeyActions, updateShouldShowSuggestionMenuToFalse, getSuggestions], + [resetSuggestions, setShouldBlockSuggestionCalc, triggerHotkeyActions, updateShouldShowSuggestionMenuToFalse, getSuggestions, checkIfSuggestionVisible], ); if (!isMentionSuggestionsMenuVisible) { diff --git a/src/pages/home/report/ReportActionCompose/Suggestions.tsx b/src/pages/home/report/ReportActionCompose/Suggestions.tsx index f82b38c3e154..9fcd7adfcd14 100644 --- a/src/pages/home/report/ReportActionCompose/Suggestions.tsx +++ b/src/pages/home/report/ReportActionCompose/Suggestions.tsx @@ -124,6 +124,11 @@ function Suggestions( suggestionEmojiRef.current?.setShouldBlockSuggestionCalc(shouldBlock); suggestionMentionRef.current?.setShouldBlockSuggestionCalc(shouldBlock); }, []); + const checkIfSuggestionVisible = useCallback(() => { + const isEmojiVisible = suggestionEmojiRef.current?.checkIfSuggestionVisible(); + const isSuggestionVisible = suggestionMentionRef.current?.checkIfSuggestionVisible(); + return isEmojiVisible ?? isSuggestionVisible ?? false; + }, []); useImperativeHandle( ref, @@ -134,8 +139,9 @@ function Suggestions( updateShouldShowSuggestionMenuToFalse, setShouldBlockSuggestionCalc, getSuggestions, + checkIfSuggestionVisible, }), - [onSelectionChange, resetSuggestions, setShouldBlockSuggestionCalc, triggerHotkeyActions, updateShouldShowSuggestionMenuToFalse, getSuggestions], + [onSelectionChange, resetSuggestions, setShouldBlockSuggestionCalc, triggerHotkeyActions, updateShouldShowSuggestionMenuToFalse, getSuggestions, checkIfSuggestionVisible], ); useEffect(() => { From be606bc7f8f1b2ac88db8c4bed636619f429aeab Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Wed, 3 Jul 2024 11:11:47 +0200 Subject: [PATCH 12/28] fix wrong positioning when focus input --- src/components/AutoCompleteSuggestions/index.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/AutoCompleteSuggestions/index.tsx b/src/components/AutoCompleteSuggestions/index.tsx index f9fc4d0c94c2..5719db5c8b0f 100644 --- a/src/components/AutoCompleteSuggestions/index.tsx +++ b/src/components/AutoCompleteSuggestions/index.tsx @@ -44,6 +44,7 @@ function AutoCompleteSuggestions({measureParentContainerAndReportCu width: 0, left: 0, bottom: 0, + cursorCoordinates: {x: 0, y: 0}, }); const StyleUtils = useStyleUtils(); const insets = useSafeAreaInsets(); @@ -66,6 +67,8 @@ function AutoCompleteSuggestions({measureParentContainerAndReportCu const suggestionsLength = props.suggestions.length; + // console.log('emoji_FOCUS', isFocused); + useEffect(() => { if (!measureParentContainerAndReportCursor) { return; @@ -111,11 +114,12 @@ function AutoCompleteSuggestions({measureParentContainerAndReportCu left: leftValue.current, bottom: bottomValue, width: widthValue, + cursorCoordinates, }); }); }, [measureParentContainerAndReportCursor, windowHeight, windowWidth, keyboardHeight, isSmallScreenWidth, suggestionsLength, bottomInset, topInset]); - if (containerState.width === 0 && containerState.left === 0 && containerState.bottom === 0) { + if ((containerState.width === 0 && containerState.left === 0 && containerState.bottom === 0) || (containerState.cursorCoordinates.x === 0 && containerState.cursorCoordinates.y === 0)) { return null; } return ( From eec0d6f94f07f6791e89039a5946b341fbd1dbba Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Wed, 3 Jul 2024 11:12:50 +0200 Subject: [PATCH 13/28] fix shortcuts and focus issue --- .../report/ReportActionItemMessageEdit.tsx | 100 +++++++++++------- 1 file changed, 64 insertions(+), 36 deletions(-) diff --git a/src/pages/home/report/ReportActionItemMessageEdit.tsx b/src/pages/home/report/ReportActionItemMessageEdit.tsx index 71e87934f94c..34397018f068 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.tsx +++ b/src/pages/home/report/ReportActionItemMessageEdit.tsx @@ -100,6 +100,7 @@ function ReportActionItemMessageEdit( const mobileInputScrollPosition = useRef(0); const cursorPositionValue = useSharedValue({x: 0, y: 0}); const tag = useSharedValue(-1); + const isInitialMount = useRef(true); const emojisPresentBefore = useRef([]); const [draft, setDraft] = useState(() => { @@ -137,11 +138,6 @@ function ReportActionItemMessageEdit( setDraft(draftMessage); }, [draftMessage, action, prevDraftMessage]); - useEffect(() => { - // required for keeping last state of isFocused variable - isFocusedRef.current = isFocused; - }, [isFocused]); - useEffect(() => { InputFocus.composerFocusKeepFocusOn(textInputRef.current as HTMLElement, isFocused, modal, onyxFocused); }, [isFocused, modal, onyxFocused]); @@ -179,25 +175,32 @@ function ReportActionItemMessageEdit( ); useEffect( - () => () => { - InputFocus.callback(() => setIsFocused(false)); - InputFocus.inputFocusChange(false); - - // Skip if the current report action is not active - if (!isActive()) { + () => { + if (isInitialMount.current) { + isInitialMount.current = false; return; } - if (EmojiPickerAction.isActive(action.reportActionID)) { - EmojiPickerAction.clearActive(); - } - if (ReportActionContextMenu.isActiveReportAction(action.reportActionID)) { - ReportActionContextMenu.clearActiveReportAction(); - } + return () => { + InputFocus.callback(() => setIsFocused(false)); + InputFocus.inputFocusChange(false); + + // Skip if the current report action is not active + if (!isActive()) { + return; + } - // Show the main composer when the focused message is deleted from another client - // to prevent the main composer stays hidden until we swtich to another chat. - setShouldShowComposeInputKeyboardAware(true); + if (EmojiPickerAction.isActive(action.reportActionID)) { + EmojiPickerAction.clearActive(); + } + if (ReportActionContextMenu.isActiveReportAction(action.reportActionID)) { + ReportActionContextMenu.clearActiveReportAction(); + } + + // Show the main composer when the focused message is deleted from another client + // to prevent the main composer stays hidden until we swtich to another chat. + setShouldShowComposeInputKeyboardAware(true); + }; }, // eslint-disable-next-line react-hooks/exhaustive-deps -- this cleanup needs to be called only on unmount [action.reportActionID], @@ -347,6 +350,21 @@ function ReportActionItemMessageEdit( updateDraft(ComposerUtils.insertText(draft, selection, `${emoji} `)); }; + const hideSuggestionMenu = useCallback(() => { + if (!suggestionsRef.current) { + return; + } + suggestionsRef.current.updateShouldShowSuggestionMenuToFalse(false); + }, [suggestionsRef]); + const onSaveScrollAndHideSuggestionMenu = useCallback( + (e: NativeSyntheticEvent) => { + mobileInputScrollPosition.current = e?.nativeEvent?.contentOffset?.y ?? 0; + + hideSuggestionMenu(); + }, + [hideSuggestionMenu], + ); + /** * Key event handlers that short cut to saving/canceling. * @@ -358,15 +376,28 @@ function ReportActionItemMessageEdit( return; } const keyEvent = e as KeyboardEvent; - if (keyEvent.key === CONST.KEYBOARD_SHORTCUTS.ENTER.shortcutKey && !keyEvent.shiftKey) { + const isShortcutEnter = keyEvent.key === CONST.KEYBOARD_SHORTCUTS.ENTER.shortcutKey; + const isShortcutEscape = keyEvent.key === CONST.KEYBOARD_SHORTCUTS.ESCAPE.shortcutKey; + const isSuggestionActive = suggestionsRef.current?.checkIfSuggestionVisible(); + + if (isSuggestionActive && isShortcutEnter) { + suggestionsRef.current?.triggerHotkeyActions(keyEvent); + return; + } + if (isShortcutEscape && isSuggestionActive) { + e.preventDefault(); + hideSuggestionMenu(); + return; + } + if (isShortcutEnter && !keyEvent.shiftKey) { e.preventDefault(); publishDraft(); - } else if (keyEvent.key === CONST.KEYBOARD_SHORTCUTS.ESCAPE.shortcutKey) { + } else if (isShortcutEscape) { e.preventDefault(); deleteDraft(); } }, - [deleteDraft, isKeyboardShown, isSmallScreenWidth, publishDraft], + [deleteDraft, hideSuggestionMenu, isKeyboardShown, isSmallScreenWidth, publishDraft], ); const measureContainer = useCallback( @@ -399,18 +430,6 @@ function ReportActionItemMessageEdit( [cursorPositionValue.value, measureContainer, selection], ); - const hideSuggestionMenu = useCallback( - (e: NativeSyntheticEvent) => { - mobileInputScrollPosition.current = e?.nativeEvent?.contentOffset?.y ?? 0; - - if (!suggestionsRef.current) { - return; - } - suggestionsRef.current.updateShouldShowSuggestionMenuToFalse(false); - }, - [suggestionsRef], - ); - useEffect(() => { tag.value = findNodeHandle(textInputRef.current) ?? -1; // eslint-disable-next-line react-hooks/exhaustive-deps @@ -440,6 +459,15 @@ function ReportActionItemMessageEdit( validateCommentMaxLength(draft, {reportID}); }, [draft, reportID, validateCommentMaxLength]); + useEffect(() => { + // required for keeping last state of isFocused variable + isFocusedRef.current = isFocused; + + if (!isFocused) { + hideSuggestionMenu(); + } + }, [isFocused, hideSuggestionMenu]); + return ( <> setSelection(e.nativeEvent.selection)} isGroupPolicyReport={isGroupPolicyReport} shouldCalculateCaretPosition - onScroll={hideSuggestionMenu} + onScroll={onSaveScrollAndHideSuggestionMenu} /> From 2ed0d9af31cd11fb2db0b0fe6995c73ed54fb2fe Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Wed, 3 Jul 2024 12:15:41 +0200 Subject: [PATCH 14/28] checkIfSuggestionVisible --- .../report/ReportActionCompose/SuggestionEmoji.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx b/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx index bc8883f371c1..c9ffa71be9f3 100644 --- a/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx +++ b/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx @@ -183,10 +183,7 @@ function SuggestionEmoji( return; } - // Avoid calling the function when keyboard animation running - InteractionManager.runAfterInteractions(() => { - calculateEmojiSuggestion(selection.start, selection.end); - }); + calculateEmojiSuggestion(selection.start, selection.end); }, [selection, calculateEmojiSuggestion, isComposerFocused]); const setShouldBlockSuggestionCalc = useCallback( @@ -198,6 +195,8 @@ function SuggestionEmoji( const getSuggestions = useCallback(() => suggestionValues.suggestedEmojis, [suggestionValues]); + const checkIfSuggestionVisible = useCallback(() => isEmojiSuggestionsMenuVisible, [isEmojiSuggestionsMenuVisible]); + useImperativeHandle( ref, () => ({ @@ -206,8 +205,9 @@ function SuggestionEmoji( setShouldBlockSuggestionCalc, updateShouldShowSuggestionMenuToFalse, getSuggestions, + checkIfSuggestionVisible, }), - [resetSuggestions, setShouldBlockSuggestionCalc, triggerHotkeyActions, updateShouldShowSuggestionMenuToFalse, getSuggestions], + [resetSuggestions, setShouldBlockSuggestionCalc, triggerHotkeyActions, updateShouldShowSuggestionMenuToFalse, getSuggestions, checkIfSuggestionVisible], ); if (!isEmojiSuggestionsMenuVisible) { From 9e8d8e0820ee2c306912526b31a035e25d59c685 Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Wed, 3 Jul 2024 16:00:44 +0200 Subject: [PATCH 15/28] lint --- src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx | 1 - src/pages/home/report/ReportActionItemMessageEdit.tsx | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx b/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx index c9ffa71be9f3..bf71937a9e9a 100644 --- a/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx +++ b/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx @@ -1,6 +1,5 @@ import type {ForwardedRef, RefAttributes} from 'react'; import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState} from 'react'; -import {InteractionManager} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import type {Emoji} from '@assets/emojis/types'; import EmojiSuggestions from '@components/EmojiSuggestions'; diff --git a/src/pages/home/report/ReportActionItemMessageEdit.tsx b/src/pages/home/report/ReportActionItemMessageEdit.tsx index 34397018f068..78d45484547e 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.tsx +++ b/src/pages/home/report/ReportActionItemMessageEdit.tsx @@ -2,8 +2,7 @@ import lodashDebounce from 'lodash/debounce'; import type {ForwardedRef} from 'react'; import React, {forwardRef, useCallback, useEffect, useMemo, useRef, useState} from 'react'; import {findNodeHandle, InteractionManager, Keyboard, View} from 'react-native'; -import type {NativeSyntheticEvent, TextInput, TextInputFocusEventData, TextInputKeyPressEventData} from 'react-native'; -import type {MeasureInWindowOnSuccessCallback, TextInputScrollEventData} from 'react-native'; +import type {MeasureInWindowOnSuccessCallback, NativeSyntheticEvent, TextInput, TextInputFocusEventData, TextInputKeyPressEventData, TextInputScrollEventData} from 'react-native'; import {useFocusedInputHandler} from 'react-native-keyboard-controller'; import {useOnyx} from 'react-native-onyx'; import {useSharedValue} from 'react-native-reanimated'; @@ -101,7 +100,6 @@ function ReportActionItemMessageEdit( const cursorPositionValue = useSharedValue({x: 0, y: 0}); const tag = useSharedValue(-1); const isInitialMount = useRef(true); - const emojisPresentBefore = useRef([]); const [draft, setDraft] = useState(() => { if (draftMessage) { From d04dec37a1019afea0cd085e15ae66eaa654391d Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Wed, 3 Jul 2024 17:14:58 +0200 Subject: [PATCH 16/28] fix 'enter' from keyboard on suggestion --- src/pages/home/report/ReportActionCompose/Suggestions.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionCompose/Suggestions.tsx b/src/pages/home/report/ReportActionCompose/Suggestions.tsx index 9fcd7adfcd14..2e5c242d155b 100644 --- a/src/pages/home/report/ReportActionCompose/Suggestions.tsx +++ b/src/pages/home/report/ReportActionCompose/Suggestions.tsx @@ -127,7 +127,8 @@ function Suggestions( const checkIfSuggestionVisible = useCallback(() => { const isEmojiVisible = suggestionEmojiRef.current?.checkIfSuggestionVisible(); const isSuggestionVisible = suggestionMentionRef.current?.checkIfSuggestionVisible(); - return isEmojiVisible ?? isSuggestionVisible ?? false; + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + return isEmojiVisible || isSuggestionVisible; }, []); useImperativeHandle( From 354f77df5b28fc75f983cf2e6395699655574e0c Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Wed, 3 Jul 2024 17:26:01 +0200 Subject: [PATCH 17/28] type --- src/pages/home/report/ReportActionCompose/Suggestions.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionCompose/Suggestions.tsx b/src/pages/home/report/ReportActionCompose/Suggestions.tsx index 2e5c242d155b..01553bd10bc2 100644 --- a/src/pages/home/report/ReportActionCompose/Suggestions.tsx +++ b/src/pages/home/report/ReportActionCompose/Suggestions.tsx @@ -124,7 +124,7 @@ function Suggestions( suggestionEmojiRef.current?.setShouldBlockSuggestionCalc(shouldBlock); suggestionMentionRef.current?.setShouldBlockSuggestionCalc(shouldBlock); }, []); - const checkIfSuggestionVisible = useCallback(() => { + const checkIfSuggestionVisible = useCallback((): boolean => { const isEmojiVisible = suggestionEmojiRef.current?.checkIfSuggestionVisible(); const isSuggestionVisible = suggestionMentionRef.current?.checkIfSuggestionVisible(); // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing From b72bf52fe2d1e69fa69beeb3b624dd5431156bc5 Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Wed, 3 Jul 2024 17:46:09 +0200 Subject: [PATCH 18/28] type --- src/pages/home/report/ReportActionCompose/Suggestions.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionCompose/Suggestions.tsx b/src/pages/home/report/ReportActionCompose/Suggestions.tsx index 01553bd10bc2..e343cf1eb877 100644 --- a/src/pages/home/report/ReportActionCompose/Suggestions.tsx +++ b/src/pages/home/report/ReportActionCompose/Suggestions.tsx @@ -128,7 +128,7 @@ function Suggestions( const isEmojiVisible = suggestionEmojiRef.current?.checkIfSuggestionVisible(); const isSuggestionVisible = suggestionMentionRef.current?.checkIfSuggestionVisible(); // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - return isEmojiVisible || isSuggestionVisible; + return isEmojiVisible || isSuggestionVisible || false; }, []); useImperativeHandle( From 507d8ac96fde715cc0f2b3b230639df0a1f32fb2 Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Fri, 5 Jul 2024 14:11:41 +0200 Subject: [PATCH 19/28] clean --- .../AutoCompleteSuggestions/index.tsx | 17 ++++++++++++----- .../report/ReportActionCompose/Suggestions.tsx | 7 +++---- .../home/report/ReportActionItemMessageEdit.tsx | 2 +- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/components/AutoCompleteSuggestions/index.tsx b/src/components/AutoCompleteSuggestions/index.tsx index 5719db5c8b0f..f1c7fb505921 100644 --- a/src/components/AutoCompleteSuggestions/index.tsx +++ b/src/components/AutoCompleteSuggestions/index.tsx @@ -26,6 +26,14 @@ function isSuggestionRenderedAbove(isEnoughSpaceAboveForBig: boolean, isEnoughSp return isEnoughSpaceAboveForBig || isEnoughSpaceAboveForSmall; } +type IsEnoughSpaceAbove = Pick & { + contentHeight: number; + topInset: number; +}; +function isEnoughSpaceAbove({y, cursorCoordinates, scrollValue, contentHeight, topInset}: IsEnoughSpaceAbove): boolean { + return y + (cursorCoordinates.y - scrollValue) > contentHeight + topInset + CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_BOX_MAX_SAFE_DISTANCE; +} + /** * On the mobile-web platform, when long-pressing on auto-complete suggestions, * we need to prevent focus shifting to avoid blurring the main input (which makes the suggestions picker close and fires the onSelect callback). @@ -67,8 +75,6 @@ function AutoCompleteSuggestions({measureParentContainerAndReportCu const suggestionsLength = props.suggestions.length; - // console.log('emoji_FOCUS', isFocused); - useEffect(() => { if (!measureParentContainerAndReportCursor) { return; @@ -85,8 +91,9 @@ function AutoCompleteSuggestions({measureParentContainerAndReportCu let bottomValue = windowHeight - (cursorCoordinates.y - scrollValue + y) - keyboardHeight; const widthValue = isSmallScreenWidth ? width : CONST.AUTO_COMPLETE_SUGGESTER.BIG_SCREEN_SUGGESTION_WIDTH; - const isEnoughSpaceAboveForBig = y + (cursorCoordinates.y - scrollValue) > contentMaxHeight + topInset + CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_BOX_MAX_SAFE_DISTANCE; - const isEnoughSpaceAboveForSmall = y + (cursorCoordinates.y - scrollValue) > contentMinHeight + topInset + CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_BOX_MAX_SAFE_DISTANCE; + const isEnoughSpaceAboveForBig = isEnoughSpaceAbove({y, cursorCoordinates, scrollValue, contentHeight: contentMaxHeight, topInset}); + const isEnoughSpaceAboveForSmall = isEnoughSpaceAbove({y, cursorCoordinates, scrollValue, contentHeight: contentMinHeight, topInset}); + const newLeftValue = isSmallScreenWidth ? x : leftValueForBigScreen; // If the suggested word is longer than 150 (approximately half the width of the suggestion popup), then adjust a new position of popup const isAdjustmentNeeded = Math.abs(prevLeftValue.current - leftValueForBigScreen) > 150; @@ -107,7 +114,7 @@ function AutoCompleteSuggestions({measureParentContainerAndReportCu } else { // calculation for big suggestion box below the cursor measuredHeight = measureHeightOfSuggestionRows(suggestionsLength, true); - bottomValue = windowHeight - y - cursorCoordinates.y + scrollValue - measuredHeight - CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_ROW_HEIGHT - keyboardHeight - 0; + bottomValue = windowHeight - y - cursorCoordinates.y + scrollValue - measuredHeight - CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_ROW_HEIGHT - keyboardHeight; } setSuggestionHeight(measuredHeight); setContainerState({ diff --git a/src/pages/home/report/ReportActionCompose/Suggestions.tsx b/src/pages/home/report/ReportActionCompose/Suggestions.tsx index e343cf1eb877..249fa0a4e721 100644 --- a/src/pages/home/report/ReportActionCompose/Suggestions.tsx +++ b/src/pages/home/report/ReportActionCompose/Suggestions.tsx @@ -125,10 +125,9 @@ function Suggestions( suggestionMentionRef.current?.setShouldBlockSuggestionCalc(shouldBlock); }, []); const checkIfSuggestionVisible = useCallback((): boolean => { - const isEmojiVisible = suggestionEmojiRef.current?.checkIfSuggestionVisible(); - const isSuggestionVisible = suggestionMentionRef.current?.checkIfSuggestionVisible(); - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - return isEmojiVisible || isSuggestionVisible || false; + const isEmojiVisible = suggestionEmojiRef.current?.checkIfSuggestionVisible() ?? false; + const isSuggestionVisible = suggestionMentionRef.current?.checkIfSuggestionVisible() ?? false; + return isEmojiVisible || isSuggestionVisible; }, []); useImperativeHandle( diff --git a/src/pages/home/report/ReportActionItemMessageEdit.tsx b/src/pages/home/report/ReportActionItemMessageEdit.tsx index 78d45484547e..76161c3d369b 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.tsx +++ b/src/pages/home/report/ReportActionItemMessageEdit.tsx @@ -405,7 +405,7 @@ function ReportActionItemMessageEdit( } containerRef.current.measureInWindow(callback); }, - // We added isComposerFullSize in dependencies so that when this value changes, we recalculate the position of the popup + // We added isFocused in dependencies so that when this value changes, we recalculate the position of the popup // eslint-disable-next-line react-hooks/exhaustive-deps [isFocused], ); From ba105c2cc6e69d60357e09b018ca2016bb330b01 Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Fri, 5 Jul 2024 16:21:31 +0200 Subject: [PATCH 20/28] remove const --- src/pages/home/report/ReportActionItemMessageEdit.tsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/pages/home/report/ReportActionItemMessageEdit.tsx b/src/pages/home/report/ReportActionItemMessageEdit.tsx index 76161c3d369b..d1a2cb3d5d56 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.tsx +++ b/src/pages/home/report/ReportActionItemMessageEdit.tsx @@ -374,23 +374,21 @@ function ReportActionItemMessageEdit( return; } const keyEvent = e as KeyboardEvent; - const isShortcutEnter = keyEvent.key === CONST.KEYBOARD_SHORTCUTS.ENTER.shortcutKey; - const isShortcutEscape = keyEvent.key === CONST.KEYBOARD_SHORTCUTS.ESCAPE.shortcutKey; const isSuggestionActive = suggestionsRef.current?.checkIfSuggestionVisible(); - if (isSuggestionActive && isShortcutEnter) { + if (isSuggestionActive && keyEvent.key === CONST.KEYBOARD_SHORTCUTS.ENTER.shortcutKey) { suggestionsRef.current?.triggerHotkeyActions(keyEvent); return; } - if (isShortcutEscape && isSuggestionActive) { + if (keyEvent.key === CONST.KEYBOARD_SHORTCUTS.ESCAPE.shortcutKey && isSuggestionActive) { e.preventDefault(); hideSuggestionMenu(); return; } - if (isShortcutEnter && !keyEvent.shiftKey) { + if (keyEvent.key === CONST.KEYBOARD_SHORTCUTS.ENTER.shortcutKey && !keyEvent.shiftKey) { e.preventDefault(); publishDraft(); - } else if (isShortcutEscape) { + } else if (keyEvent.key === CONST.KEYBOARD_SHORTCUTS.ESCAPE.shortcutKey) { e.preventDefault(); deleteDraft(); } From 1c390e574b79f1922ced182cd0cd8deed5cf6094 Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Tue, 9 Jul 2024 16:50:25 +0200 Subject: [PATCH 21/28] fix selection --- src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx b/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx index bf71937a9e9a..f8fe9871981d 100644 --- a/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx +++ b/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx @@ -150,7 +150,7 @@ function SuggestionEmoji( */ const calculateEmojiSuggestion = useCallback( (selectionStart?: number, selectionEnd?: number) => { - if (selectionStart !== selectionEnd || !selectionEnd || shouldBlockCalc.current || !value) { + if (selectionStart !== selectionEnd || !selectionEnd || shouldBlockCalc.current || !value || (selectionStart === 0 && selectionEnd === 0)) { shouldBlockCalc.current = false; resetSuggestions(); return; @@ -178,7 +178,7 @@ function SuggestionEmoji( ); useEffect(() => { - if (!isComposerFocused || (selection.start === 0 && selection.end === 0) || selection.start !== selection.end) { + if (!isComposerFocused) { return; } From e2d662b95d3d84f380bd632ec068ce25cbd14da6 Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Tue, 9 Jul 2024 17:23:50 +0200 Subject: [PATCH 22/28] remove eslint-disable --- src/pages/home/report/ReportActionItemMessageEdit.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/pages/home/report/ReportActionItemMessageEdit.tsx b/src/pages/home/report/ReportActionItemMessageEdit.tsx index d1a2cb3d5d56..244c6db1eb42 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.tsx +++ b/src/pages/home/report/ReportActionItemMessageEdit.tsx @@ -403,8 +403,6 @@ function ReportActionItemMessageEdit( } containerRef.current.measureInWindow(callback); }, - // We added isFocused in dependencies so that when this value changes, we recalculate the position of the popup - // eslint-disable-next-line react-hooks/exhaustive-deps [isFocused], ); @@ -428,7 +426,6 @@ function ReportActionItemMessageEdit( useEffect(() => { tag.value = findNodeHandle(textInputRef.current) ?? -1; - // eslint-disable-next-line react-hooks/exhaustive-deps }, []); useFocusedInputHandler( { From bc2fd143d77edb783916041546ab55f56f539352 Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Tue, 9 Jul 2024 17:58:52 +0200 Subject: [PATCH 23/28] run tag on UI --- src/pages/home/report/ReportActionItemMessageEdit.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/pages/home/report/ReportActionItemMessageEdit.tsx b/src/pages/home/report/ReportActionItemMessageEdit.tsx index 244c6db1eb42..84eab29719e0 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.tsx +++ b/src/pages/home/report/ReportActionItemMessageEdit.tsx @@ -5,7 +5,7 @@ import {findNodeHandle, InteractionManager, Keyboard, View} from 'react-native'; import type {MeasureInWindowOnSuccessCallback, NativeSyntheticEvent, TextInput, TextInputFocusEventData, TextInputKeyPressEventData, TextInputScrollEventData} from 'react-native'; import {useFocusedInputHandler} from 'react-native-keyboard-controller'; import {useOnyx} from 'react-native-onyx'; -import {useSharedValue} from 'react-native-reanimated'; +import {runOnUI, useSharedValue} from 'react-native-reanimated'; import type {Emoji} from '@assets/emojis/types'; import type {MeasureParentContainerAndCursorCallback} from '@components/AutoCompleteSuggestions/types'; import Composer from '@components/Composer'; @@ -425,8 +425,12 @@ function ReportActionItemMessageEdit( ); useEffect(() => { - tag.value = findNodeHandle(textInputRef.current) ?? -1; - }, []); + runOnUI(() => { + 'worklet'; + + tag.value = findNodeHandle(textInputRef.current) ?? -1; + })(); + }, [tag]); useFocusedInputHandler( { onSelectionChange: (event) => { From 2a73da2e4544dd5b6f27d1b2c55721dc7903f9f3 Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Tue, 9 Jul 2024 18:14:13 +0200 Subject: [PATCH 24/28] fix react-compiler/react-compiler --- src/pages/home/report/ReportActionItemMessageEdit.tsx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/pages/home/report/ReportActionItemMessageEdit.tsx b/src/pages/home/report/ReportActionItemMessageEdit.tsx index 84eab29719e0..6e75c8543ebe 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.tsx +++ b/src/pages/home/report/ReportActionItemMessageEdit.tsx @@ -425,12 +425,9 @@ function ReportActionItemMessageEdit( ); useEffect(() => { - runOnUI(() => { - 'worklet'; - - tag.value = findNodeHandle(textInputRef.current) ?? -1; - })(); - }, [tag]); + const handle = findNodeHandle(textInputRef.current) ?? -1; + tag.value = handle; + }, []); useFocusedInputHandler( { onSelectionChange: (event) => { From 8a664108a86dc54f99271ab1c6d0c146f4f6ecf9 Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Tue, 9 Jul 2024 19:16:39 +0200 Subject: [PATCH 25/28] Merge branch 'main' of https://github.com/Expensify/App into perunt/suggestion-box-edit-input --- src/pages/home/report/ReportActionItemMessageEdit.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/home/report/ReportActionItemMessageEdit.tsx b/src/pages/home/report/ReportActionItemMessageEdit.tsx index f1b48cb2af90..54e2c450ee00 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.tsx +++ b/src/pages/home/report/ReportActionItemMessageEdit.tsx @@ -425,8 +425,8 @@ function ReportActionItemMessageEdit( ); useEffect(() => { - const handle = findNodeHandle(textInputRef.current) ?? -1; - tag.value = handle; + tag.value = findNodeHandle(textInputRef.current) ?? -1; + // eslint-disable-next-line react-compiler/react-compiler, }, []); useFocusedInputHandler( { From f7d8319e3d9a3134f8de58260ce56a8b7bb209b7 Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Tue, 9 Jul 2024 19:59:35 +0200 Subject: [PATCH 26/28] eslint-disable-next-line react-compiler/react-compiler, --- src/pages/home/report/ReportActionItemMessageEdit.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/home/report/ReportActionItemMessageEdit.tsx b/src/pages/home/report/ReportActionItemMessageEdit.tsx index 54e2c450ee00..8292359742fe 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.tsx +++ b/src/pages/home/report/ReportActionItemMessageEdit.tsx @@ -5,7 +5,7 @@ import {findNodeHandle, InteractionManager, Keyboard, View} from 'react-native'; import type {MeasureInWindowOnSuccessCallback, NativeSyntheticEvent, TextInput, TextInputFocusEventData, TextInputKeyPressEventData, TextInputScrollEventData} from 'react-native'; import {useFocusedInputHandler} from 'react-native-keyboard-controller'; import {useOnyx} from 'react-native-onyx'; -import {runOnUI, useSharedValue} from 'react-native-reanimated'; +import {useSharedValue} from 'react-native-reanimated'; import type {Emoji} from '@assets/emojis/types'; import type {MeasureParentContainerAndCursorCallback} from '@components/AutoCompleteSuggestions/types'; import Composer from '@components/Composer'; @@ -425,8 +425,8 @@ function ReportActionItemMessageEdit( ); useEffect(() => { - tag.value = findNodeHandle(textInputRef.current) ?? -1; // eslint-disable-next-line react-compiler/react-compiler, + tag.value = findNodeHandle(textInputRef.current) ?? -1; }, []); useFocusedInputHandler( { From 049d4873c46451a8faa0e36efcc127790ef958a6 Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Tue, 9 Jul 2024 20:13:52 +0200 Subject: [PATCH 27/28] one more react-compiler/react-compiler --- src/pages/home/report/ReportActionItemMessageEdit.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionItemMessageEdit.tsx b/src/pages/home/report/ReportActionItemMessageEdit.tsx index 8292359742fe..05a88edff644 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.tsx +++ b/src/pages/home/report/ReportActionItemMessageEdit.tsx @@ -403,6 +403,7 @@ function ReportActionItemMessageEdit( } containerRef.current.measureInWindow(callback); }, + // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps [isFocused], ); @@ -425,8 +426,9 @@ function ReportActionItemMessageEdit( ); useEffect(() => { - // eslint-disable-next-line react-compiler/react-compiler, + // eslint-disable-next-line react-compiler/react-compiler tag.value = findNodeHandle(textInputRef.current) ?? -1; + // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps }, []); useFocusedInputHandler( { From c213eecceac18b8f0c974b9ae7dd1c97af45d9a8 Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Thu, 11 Jul 2024 10:23:58 +0200 Subject: [PATCH 28/28] naming --- .../AutoCompleteSuggestions/index.tsx | 30 +++++++++---------- .../ComposerWithSuggestions.tsx | 2 ++ .../ReportActionCompose.tsx | 2 +- .../ReportActionCompose/SuggestionEmoji.tsx | 6 ++-- .../ReportActionCompose/SuggestionMention.tsx | 6 ++-- .../ReportActionCompose/Suggestions.tsx | 10 +++---- .../report/ReportActionItemMessageEdit.tsx | 9 +++--- 7 files changed, 34 insertions(+), 31 deletions(-) diff --git a/src/components/AutoCompleteSuggestions/index.tsx b/src/components/AutoCompleteSuggestions/index.tsx index f1c7fb505921..1aa486eccd4d 100644 --- a/src/components/AutoCompleteSuggestions/index.tsx +++ b/src/components/AutoCompleteSuggestions/index.tsx @@ -22,15 +22,15 @@ const measureHeightOfSuggestionRows = (numRows: number, canBeBig: boolean): numb } return numRows * CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_ROW_HEIGHT; }; -function isSuggestionRenderedAbove(isEnoughSpaceAboveForBig: boolean, isEnoughSpaceAboveForSmall: boolean): boolean { - return isEnoughSpaceAboveForBig || isEnoughSpaceAboveForSmall; +function isSuggestionMenuRenderedAbove(isEnoughSpaceAboveForBigMenu: boolean, isEnoughSpaceAboveForSmallMenu: boolean): boolean { + return isEnoughSpaceAboveForBigMenu || isEnoughSpaceAboveForSmallMenu; } -type IsEnoughSpaceAbove = Pick & { +type IsEnoughSpaceToRenderMenuAboveCursor = Pick & { contentHeight: number; topInset: number; }; -function isEnoughSpaceAbove({y, cursorCoordinates, scrollValue, contentHeight, topInset}: IsEnoughSpaceAbove): boolean { +function isEnoughSpaceToRenderMenuAboveCursor({y, cursorCoordinates, scrollValue, contentHeight, topInset}: IsEnoughSpaceToRenderMenuAboveCursor): boolean { return y + (cursorCoordinates.y - scrollValue) > contentHeight + topInset + CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_BOX_MAX_SAFE_DISTANCE; } @@ -43,7 +43,7 @@ function isEnoughSpaceAbove({y, cursorCoordinates, scrollValue, contentHeight, t function AutoCompleteSuggestions({measureParentContainerAndReportCursor = () => {}, ...props}: AutoCompleteSuggestionsProps) { const containerRef = React.useRef(null); const isInitialRender = React.useRef(true); - const isSuggestionAboveRef = React.useRef(false); + const isSuggestionMenuAboveRef = React.useRef(false); const leftValue = React.useRef(0); const prevLeftValue = React.useRef(0); const {windowHeight, windowWidth, isSmallScreenWidth} = useWindowDimensions(); @@ -82,7 +82,7 @@ function AutoCompleteSuggestions({measureParentContainerAndReportCu measureParentContainerAndReportCursor(({x, y, width, scrollValue, cursorCoordinates}: MeasureParentContainerAndCursor) => { const xCoordinatesOfCursor = x + cursorCoordinates.x; - const leftValueForBigScreen = + const bigScreenLeftOffset = xCoordinatesOfCursor + CONST.AUTO_COMPLETE_SUGGESTER.BIG_SCREEN_SUGGESTION_WIDTH > windowWidth ? windowWidth - CONST.AUTO_COMPLETE_SUGGESTER.BIG_SCREEN_SUGGESTION_WIDTH : xCoordinatesOfCursor; @@ -91,24 +91,24 @@ function AutoCompleteSuggestions({measureParentContainerAndReportCu let bottomValue = windowHeight - (cursorCoordinates.y - scrollValue + y) - keyboardHeight; const widthValue = isSmallScreenWidth ? width : CONST.AUTO_COMPLETE_SUGGESTER.BIG_SCREEN_SUGGESTION_WIDTH; - const isEnoughSpaceAboveForBig = isEnoughSpaceAbove({y, cursorCoordinates, scrollValue, contentHeight: contentMaxHeight, topInset}); - const isEnoughSpaceAboveForSmall = isEnoughSpaceAbove({y, cursorCoordinates, scrollValue, contentHeight: contentMinHeight, topInset}); + const isEnoughSpaceToRenderMenuAboveForBig = isEnoughSpaceToRenderMenuAboveCursor({y, cursorCoordinates, scrollValue, contentHeight: contentMaxHeight, topInset}); + const isEnoughSpaceToRenderMenuAboveForSmall = isEnoughSpaceToRenderMenuAboveCursor({y, cursorCoordinates, scrollValue, contentHeight: contentMinHeight, topInset}); - const newLeftValue = isSmallScreenWidth ? x : leftValueForBigScreen; + const newLeftOffset = isSmallScreenWidth ? x : bigScreenLeftOffset; // If the suggested word is longer than 150 (approximately half the width of the suggestion popup), then adjust a new position of popup - const isAdjustmentNeeded = Math.abs(prevLeftValue.current - leftValueForBigScreen) > 150; + const isAdjustmentNeeded = Math.abs(prevLeftValue.current - bigScreenLeftOffset) > 150; if (isInitialRender.current || isAdjustmentNeeded) { - isSuggestionAboveRef.current = isSuggestionRenderedAbove(isEnoughSpaceAboveForBig, isEnoughSpaceAboveForSmall); - leftValue.current = newLeftValue; + isSuggestionMenuAboveRef.current = isSuggestionMenuRenderedAbove(isEnoughSpaceToRenderMenuAboveForBig, isEnoughSpaceToRenderMenuAboveForSmall); + leftValue.current = newLeftOffset; isInitialRender.current = false; - prevLeftValue.current = newLeftValue; + prevLeftValue.current = newLeftOffset; } let measuredHeight = 0; - if (isSuggestionAboveRef.current && isEnoughSpaceAboveForBig) { + if (isSuggestionMenuAboveRef.current && isEnoughSpaceToRenderMenuAboveForBig) { // calculation for big suggestion box above the cursor measuredHeight = measureHeightOfSuggestionRows(suggestionsLength, true); - } else if (isSuggestionAboveRef.current && isEnoughSpaceAboveForSmall) { + } else if (isSuggestionMenuAboveRef.current && isEnoughSpaceToRenderMenuAboveForSmall) { // calculation for small suggestion box above the cursor measuredHeight = measureHeightOfSuggestionRows(suggestionsLength, false); } else { diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx index 6cc55c825983..46abfba93bf5 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx @@ -748,6 +748,8 @@ function ComposerWithSuggestions( }, []); useEffect(() => { + // We use the tag to store the native ID of the text input. Later, we use it in onSelectionChange to pick up the proper text input data. + tag.value = findNodeHandle(textInputRef.current) ?? -1; // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps }, []); diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx index 49574a492f1d..9fede8068e64 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.tsx @@ -60,7 +60,7 @@ type SuggestionsRef = { updateShouldShowSuggestionMenuToFalse: (shouldShowSuggestionMenu?: boolean) => void; setShouldBlockSuggestionCalc: (shouldBlock: boolean) => void; getSuggestions: () => Mention[] | Emoji[]; - checkIfSuggestionVisible: () => boolean; + getIsSuggestionsMenuVisible: () => boolean; }; type ReportActionComposeOnyxProps = { diff --git a/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx b/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx index f8fe9871981d..8d5a544afd42 100644 --- a/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx +++ b/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx @@ -194,7 +194,7 @@ function SuggestionEmoji( const getSuggestions = useCallback(() => suggestionValues.suggestedEmojis, [suggestionValues]); - const checkIfSuggestionVisible = useCallback(() => isEmojiSuggestionsMenuVisible, [isEmojiSuggestionsMenuVisible]); + const getIsSuggestionsMenuVisible = useCallback(() => isEmojiSuggestionsMenuVisible, [isEmojiSuggestionsMenuVisible]); useImperativeHandle( ref, @@ -204,9 +204,9 @@ function SuggestionEmoji( setShouldBlockSuggestionCalc, updateShouldShowSuggestionMenuToFalse, getSuggestions, - checkIfSuggestionVisible, + getIsSuggestionsMenuVisible, }), - [resetSuggestions, setShouldBlockSuggestionCalc, triggerHotkeyActions, updateShouldShowSuggestionMenuToFalse, getSuggestions, checkIfSuggestionVisible], + [resetSuggestions, setShouldBlockSuggestionCalc, triggerHotkeyActions, updateShouldShowSuggestionMenuToFalse, getSuggestions, getIsSuggestionsMenuVisible], ); if (!isEmojiSuggestionsMenuVisible) { diff --git a/src/pages/home/report/ReportActionCompose/SuggestionMention.tsx b/src/pages/home/report/ReportActionCompose/SuggestionMention.tsx index a103e8271044..86a05bad1994 100644 --- a/src/pages/home/report/ReportActionCompose/SuggestionMention.tsx +++ b/src/pages/home/report/ReportActionCompose/SuggestionMention.tsx @@ -408,7 +408,7 @@ function SuggestionMention( ); const getSuggestions = useCallback(() => suggestionValues.suggestedMentions, [suggestionValues]); - const checkIfSuggestionVisible = useCallback(() => isMentionSuggestionsMenuVisible, [isMentionSuggestionsMenuVisible]); + const getIsSuggestionsMenuVisible = useCallback(() => isMentionSuggestionsMenuVisible, [isMentionSuggestionsMenuVisible]); useImperativeHandle( ref, @@ -418,9 +418,9 @@ function SuggestionMention( setShouldBlockSuggestionCalc, updateShouldShowSuggestionMenuToFalse, getSuggestions, - checkIfSuggestionVisible, + getIsSuggestionsMenuVisible, }), - [resetSuggestions, setShouldBlockSuggestionCalc, triggerHotkeyActions, updateShouldShowSuggestionMenuToFalse, getSuggestions, checkIfSuggestionVisible], + [resetSuggestions, setShouldBlockSuggestionCalc, triggerHotkeyActions, updateShouldShowSuggestionMenuToFalse, getSuggestions, getIsSuggestionsMenuVisible], ); if (!isMentionSuggestionsMenuVisible) { diff --git a/src/pages/home/report/ReportActionCompose/Suggestions.tsx b/src/pages/home/report/ReportActionCompose/Suggestions.tsx index 249fa0a4e721..158c60b0e89a 100644 --- a/src/pages/home/report/ReportActionCompose/Suggestions.tsx +++ b/src/pages/home/report/ReportActionCompose/Suggestions.tsx @@ -124,9 +124,9 @@ function Suggestions( suggestionEmojiRef.current?.setShouldBlockSuggestionCalc(shouldBlock); suggestionMentionRef.current?.setShouldBlockSuggestionCalc(shouldBlock); }, []); - const checkIfSuggestionVisible = useCallback((): boolean => { - const isEmojiVisible = suggestionEmojiRef.current?.checkIfSuggestionVisible() ?? false; - const isSuggestionVisible = suggestionMentionRef.current?.checkIfSuggestionVisible() ?? false; + const getIsSuggestionsMenuVisible = useCallback((): boolean => { + const isEmojiVisible = suggestionEmojiRef.current?.getIsSuggestionsMenuVisible() ?? false; + const isSuggestionVisible = suggestionMentionRef.current?.getIsSuggestionsMenuVisible() ?? false; return isEmojiVisible || isSuggestionVisible; }, []); @@ -139,9 +139,9 @@ function Suggestions( updateShouldShowSuggestionMenuToFalse, setShouldBlockSuggestionCalc, getSuggestions, - checkIfSuggestionVisible, + getIsSuggestionsMenuVisible, }), - [onSelectionChange, resetSuggestions, setShouldBlockSuggestionCalc, triggerHotkeyActions, updateShouldShowSuggestionMenuToFalse, getSuggestions, checkIfSuggestionVisible], + [onSelectionChange, resetSuggestions, setShouldBlockSuggestionCalc, triggerHotkeyActions, updateShouldShowSuggestionMenuToFalse, getSuggestions, getIsSuggestionsMenuVisible], ); useEffect(() => { diff --git a/src/pages/home/report/ReportActionItemMessageEdit.tsx b/src/pages/home/report/ReportActionItemMessageEdit.tsx index 05a88edff644..40e9a4c6bf41 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.tsx +++ b/src/pages/home/report/ReportActionItemMessageEdit.tsx @@ -374,13 +374,13 @@ function ReportActionItemMessageEdit( return; } const keyEvent = e as KeyboardEvent; - const isSuggestionActive = suggestionsRef.current?.checkIfSuggestionVisible(); + const isSuggestionsMenuVisible = suggestionsRef.current?.getIsSuggestionsMenuVisible(); - if (isSuggestionActive && keyEvent.key === CONST.KEYBOARD_SHORTCUTS.ENTER.shortcutKey) { + if (isSuggestionsMenuVisible && keyEvent.key === CONST.KEYBOARD_SHORTCUTS.ENTER.shortcutKey) { suggestionsRef.current?.triggerHotkeyActions(keyEvent); return; } - if (keyEvent.key === CONST.KEYBOARD_SHORTCUTS.ESCAPE.shortcutKey && isSuggestionActive) { + if (keyEvent.key === CONST.KEYBOARD_SHORTCUTS.ESCAPE.shortcutKey && isSuggestionsMenuVisible) { e.preventDefault(); hideSuggestionMenu(); return; @@ -426,6 +426,8 @@ function ReportActionItemMessageEdit( ); useEffect(() => { + // We use the tag to store the native ID of the text input. Later, we use it in onSelectionChange to pick up the proper text input data. + // eslint-disable-next-line react-compiler/react-compiler tag.value = findNodeHandle(textInputRef.current) ?? -1; // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps @@ -558,7 +560,6 @@ function ReportActionItemMessageEdit( updateComment={updateDraft} measureParentContainerAndReportCursor={measureParentContainerAndReportCursor} isGroupPolicyReport={false} - // Input value={draft} setValue={setDraft} selection={selection}