From 3cc730fed815558d280209e2b7c28d41070dbaf6 Mon Sep 17 00:00:00 2001 From: yh-0218 Date: Mon, 8 Jan 2024 08:42:49 +0200 Subject: [PATCH 01/10] [TS Migration] ReportActionItemMessageEdit --- src/components/Composer/types.ts | 11 ++ src/libs/EmojiUtils.ts | 4 +- src/libs/actions/InputFocus/index.ts | 10 +- ...dit.js => ReportActionItemMessageEdit.tsx} | 182 ++++++++++-------- 4 files changed, 122 insertions(+), 85 deletions(-) rename src/pages/home/report/{ReportActionItemMessageEdit.js => ReportActionItemMessageEdit.tsx} (75%) diff --git a/src/components/Composer/types.ts b/src/components/Composer/types.ts index bfdcb6715d40..d8d88970ea78 100644 --- a/src/components/Composer/types.ts +++ b/src/components/Composer/types.ts @@ -6,6 +6,12 @@ type TextSelection = { }; type ComposerProps = { + /** identify id in the text input */ + id?: string; + + /** Indicate whether input is multiline */ + multiline?: boolean; + /** Maximum number of lines in the text input */ maxLines?: number; @@ -18,6 +24,9 @@ type ComposerProps = { /** Number of lines for the comment */ numberOfLines?: number; + /** Callback method handle when the input is changed */ + onChangeText?: (numberOfLines: string) => void; + /** Callback method to update number of lines for the comment */ onNumberOfLinesChange?: (numberOfLines: number) => void; @@ -69,6 +78,8 @@ type ComposerProps = { onFocus?: (event: NativeSyntheticEvent) => void; + onBlur?: (event: NativeSyntheticEvent) => void; + /** Should make the input only scroll inside the element avoid scroll out to parent */ shouldContainScroll?: boolean; }; diff --git a/src/libs/EmojiUtils.ts b/src/libs/EmojiUtils.ts index 02d1b34c69c1..e34fa0b90fc6 100644 --- a/src/libs/EmojiUtils.ts +++ b/src/libs/EmojiUtils.ts @@ -306,7 +306,7 @@ function getAddedEmojis(currentEmojis: Emoji[], formerEmojis: Emoji[]): Emoji[] * Replace any emoji name in a text with the emoji icon. * If we're on mobile, we also add a space after the emoji granted there's no text after it. */ -function replaceEmojis(text: string, preferredSkinTone = CONST.EMOJI_DEFAULT_SKIN_TONE, lang: 'en' | 'es' = CONST.LOCALES.DEFAULT): ReplacedEmoji { +function replaceEmojis(text: string, preferredSkinTone: number = CONST.EMOJI_DEFAULT_SKIN_TONE, lang: Locale = CONST.LOCALES.DEFAULT): ReplacedEmoji { // emojisTrie is importing the emoji JSON file on the app starting and we want to avoid it const emojisTrie = require('./EmojiTrie').default; @@ -370,7 +370,7 @@ function replaceEmojis(text: string, preferredSkinTone = CONST.EMOJI_DEFAULT_SKI /** * Find all emojis in a text and replace them with their code. */ -function replaceAndExtractEmojis(text: string, preferredSkinTone = CONST.EMOJI_DEFAULT_SKIN_TONE, lang = CONST.LOCALES.DEFAULT): ReplacedEmoji { +function replaceAndExtractEmojis(text: string, preferredSkinTone: number = CONST.EMOJI_DEFAULT_SKIN_TONE, lang: Locale = CONST.LOCALES.DEFAULT): ReplacedEmoji { const {text: convertedText = '', emojis = [], cursorPosition} = replaceEmojis(text, preferredSkinTone, lang); return { diff --git a/src/libs/actions/InputFocus/index.ts b/src/libs/actions/InputFocus/index.ts index 1840b0625626..726bc76ff036 100644 --- a/src/libs/actions/InputFocus/index.ts +++ b/src/libs/actions/InputFocus/index.ts @@ -1,5 +1,9 @@ -function inputFocusChange() {} -function composerFocusKeepFocusOn() {} -const callback = () => {}; +import type { Modal } from "@src/types/onyx"; + +// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-unused-vars +function inputFocusChange(_focus: boolean) {} +// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/naming-convention +function composerFocusKeepFocusOn(_ref: HTMLElement, _isFocused: boolean, _modal: Modal, _onyxFocused: boolean) {} +const callback = (method: () => void) => method(); export {composerFocusKeepFocusOn, inputFocusChange, callback}; diff --git a/src/pages/home/report/ReportActionItemMessageEdit.js b/src/pages/home/report/ReportActionItemMessageEdit.tsx similarity index 75% rename from src/pages/home/report/ReportActionItemMessageEdit.js rename to src/pages/home/report/ReportActionItemMessageEdit.tsx index dbd3262f30d5..8b61c4624d7d 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.js +++ b/src/pages/home/report/ReportActionItemMessageEdit.tsx @@ -1,9 +1,12 @@ import ExpensiMark from 'expensify-common/lib/ExpensiMark'; import Str from 'expensify-common/lib/str'; +// eslint-disable-next-line you-dont-need-lodash-underscore/get import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; -import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; +import type {ForwardedRef} from 'react'; +import React, { useCallback, useEffect, useMemo, useRef, useState} from 'react'; import {InteractionManager, Keyboard, View} from 'react-native'; +import type {NativeSyntheticEvent, TextInput, TextInputFocusEventData, TextInputKeyPressEventData} from 'react-native'; +// eslint-disable-next-line no-restricted-imports import _ from 'underscore'; import Composer from '@components/Composer'; import EmojiPickerButton from '@components/EmojiPicker/EmojiPickerButton'; @@ -11,7 +14,6 @@ import ExceededCommentLength from '@components/ExceededCommentLength'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import PressableWithFeedback from '@components/Pressable/PressableWithFeedback'; -import refPropTypes from '@components/refPropTypes'; import Tooltip from '@components/Tooltip'; import useHandleExceedMaxCommentLength from '@hooks/useHandleExceedMaxCommentLength'; import useKeyboardState from '@hooks/useKeyboardState'; @@ -30,48 +32,39 @@ import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManag import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import setShouldShowComposeInputKeyboardAware from '@libs/setShouldShowComposeInputKeyboardAware'; -import reportPropTypes from '@pages/reportPropTypes'; import * as EmojiPickerAction from '@userActions/EmojiPickerAction'; import * as InputFocus from '@userActions/InputFocus'; import * as Report from '@userActions/Report'; import * as User from '@userActions/User'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import type { Report as ReportType, ReportAction as ReportActionType, Modal} from '@src/types/onyx'; +import type { Emoji } from '@assets/emojis/types'; import * as ReportActionContextMenu from './ContextMenu/ReportActionContextMenu'; -import reportActionPropTypes from './reportActionPropTypes'; -const propTypes = { +type ReportActionItemMessageEditProps = { /** All the data of the action */ - action: PropTypes.shape(reportActionPropTypes).isRequired, + action: ReportActionType, /** Draft message */ - draftMessage: PropTypes.string.isRequired, + draftMessage: string, /** ReportID that holds the comment we're editing */ - reportID: PropTypes.string.isRequired, + reportID: string, /** Position index of the report action in the overall report FlatList view */ - index: PropTypes.number.isRequired, - - /** A ref to forward to the text input */ - forwardedRef: refPropTypes, + index: number, /** The report currently being looked at */ // eslint-disable-next-line react/no-unused-prop-types - report: reportPropTypes, + report: ReportType, /** Whether or not the emoji picker is disabled */ - shouldDisableEmojiPicker: PropTypes.bool, + shouldDisableEmojiPicker: boolean, /** Stores user's preferred skin tone */ - preferredSkinTone: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), -}; + preferredSkinTone: number, -const defaultProps = { - forwardedRef: () => {}, - report: {}, - shouldDisableEmojiPicker: false, - preferredSkinTone: CONST.EMOJI_DEFAULT_SKIN_TONE, }; // native ids @@ -80,23 +73,35 @@ const messageEditInput = 'messageEditInput'; const isMobileSafari = Browser.isMobileSafari(); -function ReportActionItemMessageEdit(props) { +function ReportActionItemMessageEdit({ + action, + draftMessage, + reportID, + index, + shouldDisableEmojiPicker= false, + preferredSkinTone= CONST.EMOJI_DEFAULT_SKIN_TONE, + forwardedRef=() => {} + }: ReportActionItemMessageEditProps & { + forwardedRef: ForwardedRef; + }, +) { const theme = useTheme(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const reportScrollManager = useReportScrollManager(); const {translate, preferredLocale} = useLocalize(); + // @ts-expect-error TODO: Remove this once useKeyboardState (https://github.com/Expensify/App/issues/24941) is migrated to TypeScript. const {isKeyboardShown} = useKeyboardState(); const {isSmallScreenWidth} = useWindowDimensions(); const getInitialDraft = () => { - if (props.draftMessage === props.action.message[0].html) { + if (action.message && draftMessage === action.message[0].html) { // We only convert the report action message to markdown if the draft message is unchanged. const parser = new ExpensiMark(); - return parser.htmlToMarkdown(props.draftMessage).trim(); + return parser.htmlToMarkdown(draftMessage).trim(); } // We need to decode saved draft message because it's escaped before saving. - return Str.htmlDecode(props.draftMessage); + return Str.htmlDecode(draftMessage); }; const getInitialSelection = () => { @@ -107,7 +112,7 @@ function ReportActionItemMessageEdit(props) { const length = getInitialDraft().length; return {start: length, end: length}; }; - const emojisPresentBefore = useRef([]); + const emojisPresentBefore = useRef([]); const [draft, setDraft] = useState(() => { const initialDraft = getInitialDraft(); if (initialDraft) { @@ -115,23 +120,29 @@ function ReportActionItemMessageEdit(props) { } return initialDraft; }); - const [selection, setSelection] = useState(getInitialSelection); - const [isFocused, setIsFocused] = useState(false); + const [selection, setSelection] = useState<{ + start: number; + end: number; + }>(getInitialSelection); + const [isFocused, setIsFocused] = useState(false); const {hasExceededMaxCommentLength, validateCommentMaxLength} = useHandleExceedMaxCommentLength(); - const [modal, setModal] = useState(false); - const [onyxFocused, setOnyxFocused] = useState(false); + const [modal, setModal] = useState({ + willAlertModalBecomeVisible: false, + isVisible: false, + }); + const [onyxFocused, setOnyxFocused] = useState(false); - const textInputRef = useRef(null); - const isFocusedRef = useRef(false); - const insertedEmojis = useRef([]); + const textInputRef = useRef<(HTMLTextAreaElement & TextInput) | null>(null); + const isFocusedRef = useRef(false); + const insertedEmojis = useRef([]); const draftRef = useRef(draft); useEffect(() => { - if (ReportActionsUtils.isDeletedAction(props.action) || props.draftMessage === props.action.message[0].html) { + if (ReportActionsUtils.isDeletedAction(action) || action.message && draftMessage === action.message[0].html) { return; } - setDraft(Str.htmlDecode(props.draftMessage)); - }, [props.draftMessage, props.action]); + setDraft(Str.htmlDecode(draftMessage)); + }, [draftMessage, action]); useEffect(() => { // required for keeping last state of isFocused variable @@ -139,13 +150,14 @@ function ReportActionItemMessageEdit(props) { }, [isFocused]); useEffect(() => { - InputFocus.composerFocusKeepFocusOn(textInputRef.current, isFocused, modal, onyxFocused); + InputFocus.composerFocusKeepFocusOn(textInputRef.current as HTMLElement, isFocused, modal, onyxFocused); }, [isFocused, modal, onyxFocused]); useEffect(() => { const unsubscribeOnyxModal = onyxSubscribe({ key: ONYXKEYS.MODAL, callback: (modalArg) => { + // eslint-disable-next-line you-dont-need-lodash-underscore/is-null if (_.isNull(modalArg)) { return; } @@ -156,6 +168,7 @@ function ReportActionItemMessageEdit(props) { const unsubscribeOnyxFocused = onyxSubscribe({ key: ONYXKEYS.INPUT_FOCUSED, callback: (modalArg) => { + // eslint-disable-next-line you-dont-need-lodash-underscore/is-null if (_.isNull(modalArg)) { return; } @@ -170,8 +183,8 @@ function ReportActionItemMessageEdit(props) { // We consider the report action active if it's focused, its emoji picker is open or its context menu is open const isActive = useCallback( - () => isFocusedRef.current || EmojiPickerAction.isActive(props.action.reportActionID) || ReportActionContextMenu.isActiveReportAction(props.action.reportActionID), - [props.action.reportActionID], + () => isFocusedRef.current || EmojiPickerAction.isActive(action.reportActionID) || ReportActionContextMenu.isActiveReportAction(action.reportActionID), + [action.reportActionID], ); useEffect(() => { @@ -188,7 +201,8 @@ function ReportActionItemMessageEdit(props) { }); // Scroll content of textInputRef to bottom - textInputRef.current.scrollTop = textInputRef.current.scrollHeight; + if (textInputRef.current) + {textInputRef.current.scrollTop = textInputRef.current.scrollHeight;} } return () => { @@ -200,10 +214,10 @@ function ReportActionItemMessageEdit(props) { return; } - if (EmojiPickerAction.isActive(props.action.reportActionID)) { + if (EmojiPickerAction.isActive(action.reportActionID)) { EmojiPickerAction.clearActive(); } - if (ReportActionContextMenu.isActiveReportAction(props.action.reportActionID)) { + if (ReportActionContextMenu.isActiveReportAction(action.reportActionID)) { ReportActionContextMenu.clearActiveReportAction(); } @@ -212,7 +226,7 @@ function ReportActionItemMessageEdit(props) { setShouldShowComposeInputKeyboardAware(true); }; // eslint-disable-next-line react-hooks/exhaustive-deps -- this cleanup needs to be called only on unmount - }, [props.action.reportActionID]); + }, [action.reportActionID]); /** * Save the draft of the comment. This debounced so that we're not ceaselessly saving your edit. Saving the draft @@ -221,10 +235,10 @@ function ReportActionItemMessageEdit(props) { */ const debouncedSaveDraft = useMemo( () => - _.debounce((newDraft) => { - Report.saveReportActionDraft(props.reportID, props.action, newDraft); + _.debounce((newDraft: string) => { + Report.saveReportActionDraft(reportID, action, newDraft); }, 1000), - [props.reportID, props.action], + [reportID, action], ); /** @@ -246,8 +260,8 @@ function ReportActionItemMessageEdit(props) { * @param {String} newDraftInput */ const updateDraft = useCallback( - (newDraftInput) => { - const {text: newDraft, emojis, cursorPosition} = EmojiUtils.replaceAndExtractEmojis(newDraftInput, props.preferredSkinTone, preferredLocale); + (newDraftInput: string) => { + const {text: newDraft, emojis, cursorPosition} = EmojiUtils.replaceAndExtractEmojis(newDraftInput, preferredSkinTone, preferredLocale); if (!_.isEmpty(emojis)) { const newEmojis = EmojiUtils.getAddedEmojis(emojis, emojisPresentBefore.current); @@ -261,7 +275,7 @@ function ReportActionItemMessageEdit(props) { setDraft(newDraft); if (newDraftInput !== newDraft) { - const position = Math.max(selection.end + (newDraft.length - draftRef.current.length), cursorPosition || 0); + const position = Math.max(selection.end + (newDraft.length - draftRef.current.length), cursorPosition ?? 0); setSelection({ start: position, end: position, @@ -273,20 +287,20 @@ function ReportActionItemMessageEdit(props) { // We want to escape the draft message to differentiate the HTML from the report action and the HTML the user drafted. debouncedSaveDraft(_.escape(newDraft)); }, - [debouncedSaveDraft, debouncedUpdateFrequentlyUsedEmojis, props.preferredSkinTone, preferredLocale, selection.end], + [debouncedSaveDraft, debouncedUpdateFrequentlyUsedEmojis, preferredSkinTone, preferredLocale, selection.end], ); useEffect(() => { updateDraft(draft); // eslint-disable-next-line react-hooks/exhaustive-deps -- run this only when language is changed - }, [props.action.reportActionID, preferredLocale]); + }, [action.reportActionID, preferredLocale]); /** * Delete the draft of the comment being edited. This will take the comment out of "edit mode" with the old content. */ const deleteDraft = useCallback(() => { debouncedSaveDraft.cancel(); - Report.deleteReportActionDraft(props.reportID, props.action); + Report.deleteReportActionDraft(reportID, action); if (isActive()) { ReportActionComposeFocusManager.clear(); @@ -294,13 +308,13 @@ function ReportActionItemMessageEdit(props) { } // Scroll to the last comment after editing to make sure the whole comment is clearly visible in the report. - if (props.index === 0) { + if (index === 0) { const keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', () => { - reportScrollManager.scrollToIndex(props.index, false); + reportScrollManager.scrollToIndex(index, false); keyboardDidHideListener.remove(); }); } - }, [props.action, debouncedSaveDraft, props.index, props.reportID, reportScrollManager, isActive]); + }, [action, debouncedSaveDraft, index, reportID, reportScrollManager, isActive]); /** * Save the draft of the comment to be the new comment message. This will take the comment out of "edit mode" with @@ -320,18 +334,25 @@ function ReportActionItemMessageEdit(props) { // When user tries to save the empty message, it will delete it. Prompt the user to confirm deleting. if (!trimmedNewDraft) { - textInputRef.current.blur(); - ReportActionContextMenu.showDeleteModal(props.reportID, props.action, true, deleteDraft, () => InteractionManager.runAfterInteractions(() => textInputRef.current.focus())); + textInputRef.current?.blur(); + ReportActionContextMenu.showDeleteModal( + reportID, + action, + true, + deleteDraft, + // eslint-disable-next-line @typescript-eslint/no-misused-promises + () => InteractionManager.runAfterInteractions(() => textInputRef.current?.focus()) + ); return; } - Report.editReportComment(props.reportID, props.action, trimmedNewDraft); + Report.editReportComment(reportID, action, trimmedNewDraft); deleteDraft(); - }, [props.action, debouncedSaveDraft, deleteDraft, draft, props.reportID]); + }, [action, debouncedSaveDraft, deleteDraft, draft, reportID]); /** - * @param {String} emoji + * @param emoji */ - const addEmojiToTextBox = (emoji) => { + const addEmojiToTextBox = (emoji: string) => { setSelection((prevSelection) => ({ start: prevSelection.start + emoji.length + CONST.SPACE_LENGTH, end: prevSelection.start + emoji.length + CONST.SPACE_LENGTH, @@ -345,14 +366,15 @@ function ReportActionItemMessageEdit(props) { * @param {Event} e */ const triggerSaveOrCancel = useCallback( - (e) => { + (e: NativeSyntheticEvent) => { if (!e || ComposerUtils.canSkipTriggerHotkeys(isSmallScreenWidth, isKeyboardShown)) { return; } - if (e.key === CONST.KEYBOARD_SHORTCUTS.ENTER.shortcutKey && !e.shiftKey) { + const keyEvent = e as unknown as KeyboardEvent; + if (keyEvent.key === CONST.KEYBOARD_SHORTCUTS.ENTER.shortcutKey && !keyEvent.shiftKey) { e.preventDefault(); publishDraft(); - } else if (e.key === CONST.KEYBOARD_SHORTCUTS.ESCAPE.shortcutKey) { + } else if (keyEvent.key === CONST.KEYBOARD_SHORTCUTS.ESCAPE.shortcutKey) { e.preventDefault(); deleteDraft(); } @@ -404,11 +426,14 @@ function ReportActionItemMessageEdit(props) { { - ReportActionComposeFocusManager.editComposerRef.current = el; + ref={(el:TextInput & HTMLTextAreaElement) => { textInputRef.current = el; - // eslint-disable-next-line no-param-reassign - props.forwardedRef.current = el; + if (typeof forwardedRef === 'function') { + forwardedRef(el); + } else if (forwardedRef && _.has(forwardedRef, 'current')) { + // eslint-disable-next-line no-param-reassign + forwardedRef.current = el; + } }} id={messageEditInput} onChangeText={updateDraft} // Debounced saveDraftComment @@ -418,20 +443,21 @@ function ReportActionItemMessageEdit(props) { style={[styles.textInputCompose, styles.flex1, styles.bgTransparent]} onFocus={() => { setIsFocused(true); - reportScrollManager.scrollToIndex(props.index, true); + reportScrollManager.scrollToIndex(index, true); setShouldShowComposeInputKeyboardAware(false); // Clear active report action when another action gets focused - if (!EmojiPickerAction.isActive(props.action.reportActionID)) { + if (!EmojiPickerAction.isActive(action.reportActionID)) { EmojiPickerAction.clearActive(); } - if (!ReportActionContextMenu.isActiveReportAction(props.action.reportActionID)) { + if (!ReportActionContextMenu.isActiveReportAction(action.reportActionID)) { ReportActionContextMenu.clearActiveReportAction(); } }} - onBlur={(event) => { + onBlur={(event: NativeSyntheticEvent) => { setIsFocused(false); const relatedTargetId = lodashGet(event, 'nativeEvent.relatedTarget.id'); + // eslint-disable-next-line you-dont-need-lodash-underscore/contains if (_.contains([messageEditInput, emojiButtonID], relatedTargetId)) { return; } @@ -443,11 +469,11 @@ function ReportActionItemMessageEdit(props) { focus(true)} onEmojiSelected={addEmojiToTextBox} id={emojiButtonID} - emojiPickerID={props.action.reportActionID} + emojiPickerID={action.reportActionID} /> @@ -478,11 +504,9 @@ function ReportActionItemMessageEdit(props) { ); } -ReportActionItemMessageEdit.propTypes = propTypes; -ReportActionItemMessageEdit.defaultProps = defaultProps; ReportActionItemMessageEdit.displayName = 'ReportActionItemMessageEdit'; -const ReportActionItemMessageEditWithRef = React.forwardRef((props, ref) => ( +const ReportActionItemMessageEditWithRef = React.forwardRef((props: ReportActionItemMessageEditProps, ref: ForwardedRef) => ( ( /> )); -ReportActionItemMessageEditWithRef.displayName = 'ReportActionItemMessageEditWithRef'; - export default ReportActionItemMessageEditWithRef; From 97ab4455b2818cf6bf52782e65cb833ef3b7b407 Mon Sep 17 00:00:00 2001 From: yh-0218 Date: Mon, 8 Jan 2024 10:36:16 +0200 Subject: [PATCH 02/10] run prettier --- src/libs/actions/InputFocus/index.ts | 2 +- .../report/ReportActionItemMessageEdit.tsx | 61 +++++++++---------- 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/src/libs/actions/InputFocus/index.ts b/src/libs/actions/InputFocus/index.ts index 726bc76ff036..12bb43d443ea 100644 --- a/src/libs/actions/InputFocus/index.ts +++ b/src/libs/actions/InputFocus/index.ts @@ -1,4 +1,4 @@ -import type { Modal } from "@src/types/onyx"; +import type {Modal} from '@src/types/onyx'; // eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-unused-vars function inputFocusChange(_focus: boolean) {} diff --git a/src/pages/home/report/ReportActionItemMessageEdit.tsx b/src/pages/home/report/ReportActionItemMessageEdit.tsx index 8b61c4624d7d..ce5f2cf3510b 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.tsx +++ b/src/pages/home/report/ReportActionItemMessageEdit.tsx @@ -3,11 +3,12 @@ import Str from 'expensify-common/lib/str'; // eslint-disable-next-line you-dont-need-lodash-underscore/get import lodashGet from 'lodash/get'; import type {ForwardedRef} from 'react'; -import React, { useCallback, useEffect, useMemo, useRef, useState} from 'react'; +import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; import {InteractionManager, Keyboard, View} from 'react-native'; import type {NativeSyntheticEvent, TextInput, TextInputFocusEventData, TextInputKeyPressEventData} from 'react-native'; // eslint-disable-next-line no-restricted-imports import _ from 'underscore'; +import type {Emoji} from '@assets/emojis/types'; import Composer from '@components/Composer'; import EmojiPickerButton from '@components/EmojiPicker/EmojiPickerButton'; import ExceededCommentLength from '@components/ExceededCommentLength'; @@ -38,33 +39,31 @@ import * as Report from '@userActions/Report'; import * as User from '@userActions/User'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import type { Report as ReportType, ReportAction as ReportActionType, Modal} from '@src/types/onyx'; -import type { Emoji } from '@assets/emojis/types'; +import type {Modal, ReportAction as ReportActionType, Report as ReportType} from '@src/types/onyx'; import * as ReportActionContextMenu from './ContextMenu/ReportActionContextMenu'; type ReportActionItemMessageEditProps = { /** All the data of the action */ - action: ReportActionType, + action: ReportActionType; /** Draft message */ - draftMessage: string, + draftMessage: string; /** ReportID that holds the comment we're editing */ - reportID: string, + reportID: string; /** Position index of the report action in the overall report FlatList view */ - index: number, + index: number; /** The report currently being looked at */ // eslint-disable-next-line react/no-unused-prop-types - report: ReportType, + report: ReportType; /** Whether or not the emoji picker is disabled */ - shouldDisableEmojiPicker: boolean, + shouldDisableEmojiPicker: boolean; /** Stores user's preferred skin tone */ - preferredSkinTone: number, - + preferredSkinTone: number; }; // native ids @@ -74,17 +73,16 @@ const messageEditInput = 'messageEditInput'; const isMobileSafari = Browser.isMobileSafari(); function ReportActionItemMessageEdit({ - action, - draftMessage, - reportID, - index, - shouldDisableEmojiPicker= false, - preferredSkinTone= CONST.EMOJI_DEFAULT_SKIN_TONE, - forwardedRef=() => {} - }: ReportActionItemMessageEditProps & { - forwardedRef: ForwardedRef; - }, -) { + action, + draftMessage, + reportID, + index, + shouldDisableEmojiPicker = false, + preferredSkinTone = CONST.EMOJI_DEFAULT_SKIN_TONE, + forwardedRef = () => {}, +}: ReportActionItemMessageEditProps & { + forwardedRef: ForwardedRef; +}) { const theme = useTheme(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); @@ -121,8 +119,8 @@ function ReportActionItemMessageEdit({ return initialDraft; }); const [selection, setSelection] = useState<{ - start: number; - end: number; + start: number; + end: number; }>(getInitialSelection); const [isFocused, setIsFocused] = useState(false); const {hasExceededMaxCommentLength, validateCommentMaxLength} = useHandleExceedMaxCommentLength(); @@ -138,7 +136,7 @@ function ReportActionItemMessageEdit({ const draftRef = useRef(draft); useEffect(() => { - if (ReportActionsUtils.isDeletedAction(action) || action.message && draftMessage === action.message[0].html) { + if (ReportActionsUtils.isDeletedAction(action) || (action.message && draftMessage === action.message[0].html)) { return; } setDraft(Str.htmlDecode(draftMessage)); @@ -201,8 +199,9 @@ function ReportActionItemMessageEdit({ }); // Scroll content of textInputRef to bottom - if (textInputRef.current) - {textInputRef.current.scrollTop = textInputRef.current.scrollHeight;} + if (textInputRef.current) { + textInputRef.current.scrollTop = textInputRef.current.scrollHeight; + } } return () => { @@ -336,12 +335,12 @@ function ReportActionItemMessageEdit({ if (!trimmedNewDraft) { textInputRef.current?.blur(); ReportActionContextMenu.showDeleteModal( - reportID, + reportID, action, - true, + true, deleteDraft, // eslint-disable-next-line @typescript-eslint/no-misused-promises - () => InteractionManager.runAfterInteractions(() => textInputRef.current?.focus()) + () => InteractionManager.runAfterInteractions(() => textInputRef.current?.focus()), ); return; } @@ -426,7 +425,7 @@ function ReportActionItemMessageEdit({ { + ref={(el: TextInput & HTMLTextAreaElement) => { textInputRef.current = el; if (typeof forwardedRef === 'function') { forwardedRef(el); From 43b733526557fbe8c0611d4806de2702c4ccb2b2 Mon Sep 17 00:00:00 2001 From: yh-0218 Date: Mon, 8 Jan 2024 18:09:40 +0200 Subject: [PATCH 03/10] remove lodashGet & underscore --- .../report/ReportActionItemMessageEdit.tsx | 57 ++++++------------- 1 file changed, 18 insertions(+), 39 deletions(-) diff --git a/src/pages/home/report/ReportActionItemMessageEdit.tsx b/src/pages/home/report/ReportActionItemMessageEdit.tsx index ce5f2cf3510b..84f44ade43fa 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.tsx +++ b/src/pages/home/report/ReportActionItemMessageEdit.tsx @@ -1,13 +1,10 @@ import ExpensiMark from 'expensify-common/lib/ExpensiMark'; import Str from 'expensify-common/lib/str'; -// eslint-disable-next-line you-dont-need-lodash-underscore/get -import lodashGet from 'lodash/get'; +import lodashDebounce from 'lodash/debounce'; import type {ForwardedRef} from 'react'; -import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; +import React, {forwardRef, useCallback, useEffect, useMemo, useRef, useState} from 'react'; import {InteractionManager, Keyboard, View} from 'react-native'; import type {NativeSyntheticEvent, TextInput, TextInputFocusEventData, TextInputKeyPressEventData} from 'react-native'; -// eslint-disable-next-line no-restricted-imports -import _ from 'underscore'; import type {Emoji} from '@assets/emojis/types'; import Composer from '@components/Composer'; import EmojiPickerButton from '@components/EmojiPicker/EmojiPickerButton'; @@ -40,6 +37,7 @@ import * as User from '@userActions/User'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Modal, ReportAction as ReportActionType, Report as ReportType} from '@src/types/onyx'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; import * as ReportActionContextMenu from './ContextMenu/ReportActionContextMenu'; type ReportActionItemMessageEditProps = { @@ -72,23 +70,15 @@ const messageEditInput = 'messageEditInput'; const isMobileSafari = Browser.isMobileSafari(); -function ReportActionItemMessageEdit({ - action, - draftMessage, - reportID, - index, - shouldDisableEmojiPicker = false, - preferredSkinTone = CONST.EMOJI_DEFAULT_SKIN_TONE, - forwardedRef = () => {}, -}: ReportActionItemMessageEditProps & { - forwardedRef: ForwardedRef; -}) { +function ReportActionItemMessageEdit( + {action, draftMessage, reportID, index, shouldDisableEmojiPicker = false, preferredSkinTone = CONST.EMOJI_DEFAULT_SKIN_TONE}: ReportActionItemMessageEditProps, + forwardedRef: ForwardedRef, +) { const theme = useTheme(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const reportScrollManager = useReportScrollManager(); const {translate, preferredLocale} = useLocalize(); - // @ts-expect-error TODO: Remove this once useKeyboardState (https://github.com/Expensify/App/issues/24941) is migrated to TypeScript. const {isKeyboardShown} = useKeyboardState(); const {isSmallScreenWidth} = useWindowDimensions(); @@ -155,8 +145,7 @@ function ReportActionItemMessageEdit({ const unsubscribeOnyxModal = onyxSubscribe({ key: ONYXKEYS.MODAL, callback: (modalArg) => { - // eslint-disable-next-line you-dont-need-lodash-underscore/is-null - if (_.isNull(modalArg)) { + if (isEmptyObject(modalArg)) { return; } setModal(modalArg); @@ -166,8 +155,7 @@ function ReportActionItemMessageEdit({ const unsubscribeOnyxFocused = onyxSubscribe({ key: ONYXKEYS.INPUT_FOCUSED, callback: (modalArg) => { - // eslint-disable-next-line you-dont-need-lodash-underscore/is-null - if (_.isNull(modalArg)) { + if (isEmptyObject(modalArg)) { return; } setOnyxFocused(modalArg); @@ -234,7 +222,7 @@ function ReportActionItemMessageEdit({ */ const debouncedSaveDraft = useMemo( () => - _.debounce((newDraft: string) => { + lodashDebounce((newDraft: string) => { Report.saveReportActionDraft(reportID, action, newDraft); }, 1000), [reportID, action], @@ -246,7 +234,7 @@ function ReportActionItemMessageEdit({ */ const debouncedUpdateFrequentlyUsedEmojis = useMemo( () => - _.debounce(() => { + lodashDebounce(() => { User.updateFrequentlyUsedEmojis(EmojiUtils.getFrequentlyUsedEmojis(insertedEmojis.current)); insertedEmojis.current = []; }, 1000), @@ -262,9 +250,9 @@ function ReportActionItemMessageEdit({ (newDraftInput: string) => { const {text: newDraft, emojis, cursorPosition} = EmojiUtils.replaceAndExtractEmojis(newDraftInput, preferredSkinTone, preferredLocale); - if (!_.isEmpty(emojis)) { + if (emojis && emojis.length > 0) { const newEmojis = EmojiUtils.getAddedEmojis(emojis, emojisPresentBefore.current); - if (!_.isEmpty(newEmojis)) { + if (newEmojis && newEmojis.length > 0) { insertedEmojis.current = [...insertedEmojis.current, ...newEmojis]; debouncedUpdateFrequentlyUsedEmojis(); } @@ -284,7 +272,7 @@ function ReportActionItemMessageEdit({ draftRef.current = newDraft; // We want to escape the draft message to differentiate the HTML from the report action and the HTML the user drafted. - debouncedSaveDraft(_.escape(newDraft)); + debouncedSaveDraft(encodeURI(newDraft)); }, [debouncedSaveDraft, debouncedUpdateFrequentlyUsedEmojis, preferredSkinTone, preferredLocale, selection.end], ); @@ -429,7 +417,7 @@ function ReportActionItemMessageEdit({ textInputRef.current = el; if (typeof forwardedRef === 'function') { forwardedRef(el); - } else if (forwardedRef && _.has(forwardedRef, 'current')) { + } else if (forwardedRef) { // eslint-disable-next-line no-param-reassign forwardedRef.current = el; } @@ -455,9 +443,8 @@ function ReportActionItemMessageEdit({ }} onBlur={(event: NativeSyntheticEvent) => { setIsFocused(false); - const relatedTargetId = lodashGet(event, 'nativeEvent.relatedTarget.id'); - // eslint-disable-next-line you-dont-need-lodash-underscore/contains - if (_.contains([messageEditInput, emojiButtonID], relatedTargetId)) { + const relatedTargetId = event.nativeEvent?.relatedTarget?.id; + if (relatedTargetId && [messageEditInput, emojiButtonID].includes(relatedTargetId)) { return; } setShouldShowComposeInputKeyboardAware(true); @@ -505,12 +492,4 @@ function ReportActionItemMessageEdit({ ReportActionItemMessageEdit.displayName = 'ReportActionItemMessageEdit'; -const ReportActionItemMessageEditWithRef = React.forwardRef((props: ReportActionItemMessageEditProps, ref: ForwardedRef) => ( - -)); - -export default ReportActionItemMessageEditWithRef; +export default forwardRef(ReportActionItemMessageEdit); From 94f6ae221a842b62c584b3d48a8cebad1982313e Mon Sep 17 00:00:00 2001 From: yh-0218 Date: Mon, 8 Jan 2024 18:26:35 +0200 Subject: [PATCH 04/10] ignore isKeyboardShown null value issue --- src/pages/home/report/ReportActionItemMessageEdit.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/home/report/ReportActionItemMessageEdit.tsx b/src/pages/home/report/ReportActionItemMessageEdit.tsx index 84f44ade43fa..0ec54dbead12 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.tsx +++ b/src/pages/home/report/ReportActionItemMessageEdit.tsx @@ -79,6 +79,7 @@ function ReportActionItemMessageEdit( const StyleUtils = useStyleUtils(); const reportScrollManager = useReportScrollManager(); const {translate, preferredLocale} = useLocalize(); + // @ts-expect-error TODO: Remove this once useKeyboardState remove null value. const {isKeyboardShown} = useKeyboardState(); const {isSmallScreenWidth} = useWindowDimensions(); @@ -443,6 +444,7 @@ function ReportActionItemMessageEdit( }} onBlur={(event: NativeSyntheticEvent) => { setIsFocused(false); + // @ts-expect-error TODO: TextInputFocusEventData doesn't contain relatedTarget. const relatedTargetId = event.nativeEvent?.relatedTarget?.id; if (relatedTargetId && [messageEditInput, emojiButtonID].includes(relatedTargetId)) { return; From fcc7b163093a439a047ceba8bfdf3f293aebfdc0 Mon Sep 17 00:00:00 2001 From: yh-0218 Date: Mon, 8 Jan 2024 23:05:32 +0200 Subject: [PATCH 05/10] fixed useKeyboardState migrate issue --- src/components/withKeyboardState.tsx | 4 +++- src/hooks/useKeyboardState.ts | 2 +- src/pages/home/report/ReportActionItemMessageEdit.tsx | 1 - 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/withKeyboardState.tsx b/src/components/withKeyboardState.tsx index 2a74fd3e738e..74d10945fbcb 100755 --- a/src/components/withKeyboardState.tsx +++ b/src/components/withKeyboardState.tsx @@ -16,7 +16,9 @@ const keyboardStatePropTypes = { isKeyboardShown: PropTypes.bool.isRequired, }; -const KeyboardStateContext = createContext(null); +const KeyboardStateContext = createContext({ + isKeyboardShown: false, +}); function KeyboardStateProvider({children}: ChildrenProps): ReactElement | null { const [isKeyboardShown, setIsKeyboardShown] = useState(false); diff --git a/src/hooks/useKeyboardState.ts b/src/hooks/useKeyboardState.ts index 439f626ddcdd..60ad3b8975b1 100644 --- a/src/hooks/useKeyboardState.ts +++ b/src/hooks/useKeyboardState.ts @@ -6,6 +6,6 @@ import {KeyboardStateContext} from '@components/withKeyboardState'; * Hook for getting current state of keyboard * whether the keyboard is open */ -export default function useKeyboardState(): KeyboardStateContextValue | null { +export default function useKeyboardState(): KeyboardStateContextValue { return useContext(KeyboardStateContext); } diff --git a/src/pages/home/report/ReportActionItemMessageEdit.tsx b/src/pages/home/report/ReportActionItemMessageEdit.tsx index 0ec54dbead12..bf56eb4657e2 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.tsx +++ b/src/pages/home/report/ReportActionItemMessageEdit.tsx @@ -79,7 +79,6 @@ function ReportActionItemMessageEdit( const StyleUtils = useStyleUtils(); const reportScrollManager = useReportScrollManager(); const {translate, preferredLocale} = useLocalize(); - // @ts-expect-error TODO: Remove this once useKeyboardState remove null value. const {isKeyboardShown} = useKeyboardState(); const {isSmallScreenWidth} = useWindowDimensions(); From 4d50d8d1e9595f68b926be32b3e2ac2c6041101f Mon Sep 17 00:00:00 2001 From: yh-0218 Date: Mon, 8 Jan 2024 23:28:05 +0200 Subject: [PATCH 06/10] fixed useKeyboardState migrate issue --- src/components/HeaderWithBackButton/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/HeaderWithBackButton/index.tsx b/src/components/HeaderWithBackButton/index.tsx index 209803f2a5d1..6cbfde0645de 100755 --- a/src/components/HeaderWithBackButton/index.tsx +++ b/src/components/HeaderWithBackButton/index.tsx @@ -61,7 +61,6 @@ function HeaderWithBackButton({ const StyleUtils = useStyleUtils(); const [isDownloadButtonActive, temporarilyDisableDownloadButton] = useThrottledButtonState(); const {translate} = useLocalize(); - // @ts-expect-error TODO: Remove this once useKeyboardState (https://github.com/Expensify/App/issues/24941) is migrated to TypeScript. const {isKeyboardShown} = useKeyboardState(); const waitForNavigate = useWaitForNavigation(); From 4510296a3b42d9ed3d9dc76558fb8511d37ec5c5 Mon Sep 17 00:00:00 2001 From: yh-0218 Date: Tue, 9 Jan 2024 14:34:35 +0200 Subject: [PATCH 07/10] update condition using third conditional --- .../report/ReportActionItemMessageEdit.tsx | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/pages/home/report/ReportActionItemMessageEdit.tsx b/src/pages/home/report/ReportActionItemMessageEdit.tsx index bf56eb4657e2..c700645fb20b 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.tsx +++ b/src/pages/home/report/ReportActionItemMessageEdit.tsx @@ -36,13 +36,12 @@ import * as Report from '@userActions/Report'; import * as User from '@userActions/User'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {Modal, ReportAction as ReportActionType, Report as ReportType} from '@src/types/onyx'; -import {isEmptyObject} from '@src/types/utils/EmptyObject'; +import type * as OnyxTypes from '@src/types/onyx'; import * as ReportActionContextMenu from './ContextMenu/ReportActionContextMenu'; type ReportActionItemMessageEditProps = { /** All the data of the action */ - action: ReportActionType; + action: OnyxTypes.ReportAction; /** Draft message */ draftMessage: string; @@ -55,13 +54,13 @@ type ReportActionItemMessageEditProps = { /** The report currently being looked at */ // eslint-disable-next-line react/no-unused-prop-types - report: ReportType; + report?: OnyxTypes.Report; /** Whether or not the emoji picker is disabled */ - shouldDisableEmojiPicker: boolean; + shouldDisableEmojiPicker?: boolean; /** Stores user's preferred skin tone */ - preferredSkinTone: number; + preferredSkinTone?: number; }; // native ids @@ -83,7 +82,7 @@ function ReportActionItemMessageEdit( const {isSmallScreenWidth} = useWindowDimensions(); const getInitialDraft = () => { - if (action.message && draftMessage === action.message[0].html) { + if (draftMessage === action?.message?.[0].html) { // We only convert the report action message to markdown if the draft message is unchanged. const parser = new ExpensiMark(); return parser.htmlToMarkdown(draftMessage).trim(); @@ -114,7 +113,7 @@ function ReportActionItemMessageEdit( }>(getInitialSelection); const [isFocused, setIsFocused] = useState(false); const {hasExceededMaxCommentLength, validateCommentMaxLength} = useHandleExceedMaxCommentLength(); - const [modal, setModal] = useState({ + const [modal, setModal] = useState({ willAlertModalBecomeVisible: false, isVisible: false, }); @@ -145,7 +144,7 @@ function ReportActionItemMessageEdit( const unsubscribeOnyxModal = onyxSubscribe({ key: ONYXKEYS.MODAL, callback: (modalArg) => { - if (isEmptyObject(modalArg)) { + if (modalArg === null) { return; } setModal(modalArg); @@ -155,7 +154,7 @@ function ReportActionItemMessageEdit( const unsubscribeOnyxFocused = onyxSubscribe({ key: ONYXKEYS.INPUT_FOCUSED, callback: (modalArg) => { - if (isEmptyObject(modalArg)) { + if (modalArg === null) { return; } setOnyxFocused(modalArg); @@ -250,9 +249,9 @@ function ReportActionItemMessageEdit( (newDraftInput: string) => { const {text: newDraft, emojis, cursorPosition} = EmojiUtils.replaceAndExtractEmojis(newDraftInput, preferredSkinTone, preferredLocale); - if (emojis && emojis.length > 0) { + if (emojis?.length > 0) { const newEmojis = EmojiUtils.getAddedEmojis(emojis, emojisPresentBefore.current); - if (newEmojis && newEmojis.length > 0) { + if (newEmojis?.length > 0) { insertedEmojis.current = [...insertedEmojis.current, ...newEmojis]; debouncedUpdateFrequentlyUsedEmojis(); } @@ -353,11 +352,11 @@ function ReportActionItemMessageEdit( * @param {Event} e */ const triggerSaveOrCancel = useCallback( - (e: NativeSyntheticEvent) => { + (e: NativeSyntheticEvent | KeyboardEvent) => { if (!e || ComposerUtils.canSkipTriggerHotkeys(isSmallScreenWidth, isKeyboardShown)) { return; } - const keyEvent = e as unknown as KeyboardEvent; + const keyEvent = e as KeyboardEvent; if (keyEvent.key === CONST.KEYBOARD_SHORTCUTS.ENTER.shortcutKey && !keyEvent.shiftKey) { e.preventDefault(); publishDraft(); From c24586f8f2e7bf850a9ae57c27f9563eab14e6f6 Mon Sep 17 00:00:00 2001 From: yh-0218 Date: Tue, 9 Jan 2024 16:25:31 +0200 Subject: [PATCH 08/10] fixed special letter issue --- src/pages/home/report/ReportActionItemMessageEdit.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pages/home/report/ReportActionItemMessageEdit.tsx b/src/pages/home/report/ReportActionItemMessageEdit.tsx index c700645fb20b..7f5bd5636d90 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.tsx +++ b/src/pages/home/report/ReportActionItemMessageEdit.tsx @@ -270,8 +270,7 @@ function ReportActionItemMessageEdit( draftRef.current = newDraft; - // We want to escape the draft message to differentiate the HTML from the report action and the HTML the user drafted. - debouncedSaveDraft(encodeURI(newDraft)); + debouncedSaveDraft(newDraft); }, [debouncedSaveDraft, debouncedUpdateFrequentlyUsedEmojis, preferredSkinTone, preferredLocale, selection.end], ); From dd0740f5b1d6135a1ba2741c3a9c6d4481cca814 Mon Sep 17 00:00:00 2001 From: yh-0218 Date: Wed, 10 Jan 2024 07:50:56 +0200 Subject: [PATCH 09/10] add comment for debouncedSaveDraft --- src/pages/home/report/ReportActionItemMessageEdit.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/home/report/ReportActionItemMessageEdit.tsx b/src/pages/home/report/ReportActionItemMessageEdit.tsx index 7f5bd5636d90..5934c4c333cb 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.tsx +++ b/src/pages/home/report/ReportActionItemMessageEdit.tsx @@ -270,6 +270,7 @@ function ReportActionItemMessageEdit( draftRef.current = newDraft; + // We want to escape the draft message to differentiate the HTML from the report action and the HTML the user drafted. debouncedSaveDraft(newDraft); }, [debouncedSaveDraft, debouncedUpdateFrequentlyUsedEmojis, preferredSkinTone, preferredLocale, selection.end], From c8761cb65624c8c9f9ff4242aad56839797469d6 Mon Sep 17 00:00:00 2001 From: yh-0218 Date: Wed, 10 Jan 2024 18:15:52 +0200 Subject: [PATCH 10/10] update to modal type --- src/libs/actions/InputFocus/index.desktop.ts | 3 ++- src/libs/actions/InputFocus/index.ts | 8 ++++---- src/libs/actions/InputFocus/index.website.ts | 3 ++- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/libs/actions/InputFocus/index.desktop.ts b/src/libs/actions/InputFocus/index.desktop.ts index 86a562f0531e..2a8fe1b9fd01 100644 --- a/src/libs/actions/InputFocus/index.desktop.ts +++ b/src/libs/actions/InputFocus/index.desktop.ts @@ -1,13 +1,14 @@ import Onyx from 'react-native-onyx'; import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManager'; import ONYXKEYS from '@src/ONYXKEYS'; +import type {Modal} from '@src/types/onyx'; function inputFocusChange(focus: boolean) { Onyx.set(ONYXKEYS.INPUT_FOCUSED, focus); } let refSave: HTMLElement | undefined; -function composerFocusKeepFocusOn(ref: HTMLElement, isFocused: boolean, modal: {willAlertModalBecomeVisible: boolean; isVisible: boolean}, onyxFocused: boolean) { +function composerFocusKeepFocusOn(ref: HTMLElement, isFocused: boolean, modal: Modal, onyxFocused: boolean) { if (isFocused && !onyxFocused) { inputFocusChange(true); ref.focus(); diff --git a/src/libs/actions/InputFocus/index.ts b/src/libs/actions/InputFocus/index.ts index 12bb43d443ea..6d8706ebdd0e 100644 --- a/src/libs/actions/InputFocus/index.ts +++ b/src/libs/actions/InputFocus/index.ts @@ -1,9 +1,9 @@ import type {Modal} from '@src/types/onyx'; -// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-unused-vars -function inputFocusChange(_focus: boolean) {} -// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/naming-convention -function composerFocusKeepFocusOn(_ref: HTMLElement, _isFocused: boolean, _modal: Modal, _onyxFocused: boolean) {} +// eslint-disable-next-line @typescript-eslint/no-unused-vars +function inputFocusChange(focus: boolean) {} +// eslint-disable-next-line @typescript-eslint/no-unused-vars +function composerFocusKeepFocusOn(ref: HTMLElement, isFocused: boolean, modal: Modal, onyxFocused: boolean) {} const callback = (method: () => void) => method(); export {composerFocusKeepFocusOn, inputFocusChange, callback}; diff --git a/src/libs/actions/InputFocus/index.website.ts b/src/libs/actions/InputFocus/index.website.ts index 8e41e06d7401..541254ac0cda 100644 --- a/src/libs/actions/InputFocus/index.website.ts +++ b/src/libs/actions/InputFocus/index.website.ts @@ -2,13 +2,14 @@ import Onyx from 'react-native-onyx'; import * as Browser from '@libs/Browser'; import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManager'; import ONYXKEYS from '@src/ONYXKEYS'; +import type {Modal} from '@src/types/onyx'; function inputFocusChange(focus: boolean) { Onyx.set(ONYXKEYS.INPUT_FOCUSED, focus); } let refSave: HTMLElement | undefined; -function composerFocusKeepFocusOn(ref: HTMLElement, isFocused: boolean, modal: {willAlertModalBecomeVisible: boolean; isVisible: boolean}, onyxFocused: boolean) { +function composerFocusKeepFocusOn(ref: HTMLElement, isFocused: boolean, modal: Modal, onyxFocused: boolean) { if (isFocused && !onyxFocused) { inputFocusChange(true); ref.focus();