diff --git a/src/components/SidePanel/SidePanelModal/index.tsx b/src/components/SidePanel/SidePanelModal/index.tsx index fb85ae00333f9..5ca75c671a859 100644 --- a/src/components/SidePanel/SidePanelModal/index.tsx +++ b/src/components/SidePanel/SidePanelModal/index.tsx @@ -51,12 +51,16 @@ function SidePanelModal({children, sidePanelTranslateX, closeSidePanel, shouldHi // Web back button: push history state and close Side Panel on popstate useEffect(() => { + // Side Panel is not a normal modal on ExtraLargeScreenWidth. + if (isExtraLargeScreenWidth) { + return; + } ComposerFocusManager.resetReadyToFocus(uniqueModalId); return () => { ComposerFocusManager.setReadyToFocus(uniqueModalId); }; // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + }, [isExtraLargeScreenWidth]); return ( diff --git a/src/libs/ReportActionComposeFocusManager.ts b/src/libs/ReportActionComposeFocusManager.ts index 435468cb8a0e4..98e46daf7f80b 100644 --- a/src/libs/ReportActionComposeFocusManager.ts +++ b/src/libs/ReportActionComposeFocusManager.ts @@ -12,6 +12,10 @@ type ComposerType = 'main' | 'edit'; type FocusCallback = (shouldFocusForNonBlurInputOnTapOutside?: boolean) => void; const composerRef: RefObject = React.createRef(); +/** + * There can be 2 composers present at the same time. This ref is for the side panel. + */ +const sidePanelComposerRef: RefObject = React.createRef(); // There are two types of composer: general composer (edit composer) and main composer. // The general composer callback will take priority if it exists. @@ -104,6 +108,7 @@ function preventEditComposerFocusOnFirstResponderOnce() { export default { composerRef, + sidePanelComposerRef, onComposerFocus, focus, clear, diff --git a/src/pages/inbox/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx b/src/pages/inbox/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx index 5b957d6a45d3d..ff903d77e125e 100644 --- a/src/pages/inbox/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx +++ b/src/pages/inbox/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx @@ -22,6 +22,7 @@ import Composer from '@components/Composer'; import type {CustomSelectionChangeEvent, TextSelection} from '@components/Composer/types'; import {useWideRHPState} from '@components/WideRHPContextProvider'; import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; +import useIsInSidePanel from '@hooks/useIsInSidePanel'; import useKeyboardState from '@hooks/useKeyboardState'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; @@ -263,6 +264,7 @@ function ComposerWithSuggestions({ const mobileInputScrollPosition = useRef(0); const cursorPositionValue = useSharedValue({x: 0, y: 0}); const tag = useSharedValue(-1); + const isInSidePanel = useIsInSidePanel(); const [draftComment = ''] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT}${reportID}`); const [value, setValue] = useState(() => { if (draftComment) { @@ -683,6 +685,17 @@ function ComposerWithSuggestions({ }; }, [focus, route.key, shouldAutoFocus, shouldDelayAutoFocus]); + /** + * Tracks whether there is a composer input inside the side panel on the screen. + */ + const handleSidePanelFocus = useCallback(() => { + if (!isInSidePanel) { + ReportActionComposeFocusManager.sidePanelComposerRef.current = null; + } else { + ReportActionComposeFocusManager.sidePanelComposerRef.current = textInputRef.current; + } + }, [isInSidePanel]); + /** * Set focus callback * @param shouldTakeOverFocus - Whether this composer should gain focus priority @@ -690,6 +703,7 @@ function ComposerWithSuggestions({ const setUpComposeFocusManager = useCallback( (shouldTakeOverFocus = false) => { ReportActionComposeFocusManager.onComposerFocus((shouldFocusForNonBlurInputOnTapOutside = false) => { + handleSidePanelFocus(); if ((!willBlurTextInputOnTapOutside && !shouldFocusForNonBlurInputOnTapOutside) || !isFocused || !isSidePanelHiddenOrLargeScreen) { return; } @@ -697,7 +711,7 @@ function ComposerWithSuggestions({ focus(true); }, shouldTakeOverFocus); }, - [focus, isFocused, isSidePanelHiddenOrLargeScreen], + [focus, isFocused, isSidePanelHiddenOrLargeScreen, handleSidePanelFocus], ); /** @@ -797,6 +811,11 @@ function ComposerWithSuggestions({ return; } + // Do not focus side panels composer if it wasn't focused before + if (isInSidePanel && !ReportActionComposeFocusManager.sidePanelComposerRef.current) { + return; + } + // Do not focus the composer if the Side Panel is visible if (!isSidePanelHiddenOrLargeScreen) { return; @@ -814,7 +833,7 @@ function ComposerWithSuggestions({ return; } focus(true); - }, [focus, prevIsFocused, editFocused, prevIsModalVisible, isFocused, modal?.isVisible, isNextModalWillOpenRef, shouldAutoFocus, isSidePanelHiddenOrLargeScreen]); + }, [focus, prevIsFocused, editFocused, prevIsModalVisible, isFocused, modal?.isVisible, isNextModalWillOpenRef, shouldAutoFocus, isSidePanelHiddenOrLargeScreen, isInSidePanel]); useEffect(() => { // Scrolls the composer to the bottom and sets the selection to the end, so that longer drafts are easier to edit @@ -913,10 +932,10 @@ function ComposerWithSuggestions({ ); const handleFocus = useCallback(() => { - // The last composer that had focus should re-gain focus - setUpComposeFocusManager(true); + handleSidePanelFocus(); + setUpComposeFocusManager(!isInSidePanel); onFocus(); - }, [onFocus, setUpComposeFocusManager]); + }, [onFocus, setUpComposeFocusManager, handleSidePanelFocus, isInSidePanel]); // When using the suggestions box (Suggestions) we need to imperatively // set the cursor to the end of the suggestion/mention after it's selected.