Skip to content

Commit aff1e0c

Browse files
authored
Merge pull request #86658 from software-mansion-labs/fix/composer-sidepanel-focus
Fix: Focus jumps to Concierge Anywhere (SidePanel) when switching chats in the Inbox
2 parents 149f8ab + 72f8675 commit aff1e0c

3 files changed

Lines changed: 34 additions & 6 deletions

File tree

src/components/SidePanel/SidePanelModal/index.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,16 @@ function SidePanelModal({children, sidePanelTranslateX, closeSidePanel, shouldHi
5151

5252
// Web back button: push history state and close Side Panel on popstate
5353
useEffect(() => {
54+
// Side Panel is not a normal modal on ExtraLargeScreenWidth.
55+
if (isExtraLargeScreenWidth) {
56+
return;
57+
}
5458
ComposerFocusManager.resetReadyToFocus(uniqueModalId);
5559
return () => {
5660
ComposerFocusManager.setReadyToFocus(uniqueModalId);
5761
};
5862
// eslint-disable-next-line react-hooks/exhaustive-deps
59-
}, []);
63+
}, [isExtraLargeScreenWidth]);
6064

6165
return (
6266
<ModalPortal>

src/libs/ReportActionComposeFocusManager.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ type ComposerType = 'main' | 'edit';
1212
type FocusCallback = (shouldFocusForNonBlurInputOnTapOutside?: boolean) => void;
1313

1414
const composerRef: RefObject<TextInput | null> = React.createRef<TextInput>();
15+
/**
16+
* There can be 2 composers present at the same time. This ref is for the side panel.
17+
*/
18+
const sidePanelComposerRef: RefObject<TextInput | null> = React.createRef<TextInput>();
1519

1620
// There are two types of composer: general composer (edit composer) and main composer.
1721
// The general composer callback will take priority if it exists.
@@ -104,6 +108,7 @@ function preventEditComposerFocusOnFirstResponderOnce() {
104108

105109
export default {
106110
composerRef,
111+
sidePanelComposerRef,
107112
onComposerFocus,
108113
focus,
109114
clear,

src/pages/inbox/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.tsx

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import Composer from '@components/Composer';
2222
import type {CustomSelectionChangeEvent, TextSelection} from '@components/Composer/types';
2323
import {useWideRHPState} from '@components/WideRHPContextProvider';
2424
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
25+
import useIsInSidePanel from '@hooks/useIsInSidePanel';
2526
import useKeyboardState from '@hooks/useKeyboardState';
2627
import useLocalize from '@hooks/useLocalize';
2728
import useOnyx from '@hooks/useOnyx';
@@ -263,6 +264,7 @@ function ComposerWithSuggestions({
263264
const mobileInputScrollPosition = useRef(0);
264265
const cursorPositionValue = useSharedValue({x: 0, y: 0});
265266
const tag = useSharedValue(-1);
267+
const isInSidePanel = useIsInSidePanel();
266268
const [draftComment = ''] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT}${reportID}`);
267269
const [value, setValue] = useState(() => {
268270
if (draftComment) {
@@ -683,21 +685,33 @@ function ComposerWithSuggestions({
683685
};
684686
}, [focus, route.key, shouldAutoFocus, shouldDelayAutoFocus]);
685687

688+
/**
689+
* Tracks whether there is a composer input inside the side panel on the screen.
690+
*/
691+
const handleSidePanelFocus = useCallback(() => {
692+
if (!isInSidePanel) {
693+
ReportActionComposeFocusManager.sidePanelComposerRef.current = null;
694+
} else {
695+
ReportActionComposeFocusManager.sidePanelComposerRef.current = textInputRef.current;
696+
}
697+
}, [isInSidePanel]);
698+
686699
/**
687700
* Set focus callback
688701
* @param shouldTakeOverFocus - Whether this composer should gain focus priority
689702
*/
690703
const setUpComposeFocusManager = useCallback(
691704
(shouldTakeOverFocus = false) => {
692705
ReportActionComposeFocusManager.onComposerFocus((shouldFocusForNonBlurInputOnTapOutside = false) => {
706+
handleSidePanelFocus();
693707
if ((!willBlurTextInputOnTapOutside && !shouldFocusForNonBlurInputOnTapOutside) || !isFocused || !isSidePanelHiddenOrLargeScreen) {
694708
return;
695709
}
696710

697711
focus(true);
698712
}, shouldTakeOverFocus);
699713
},
700-
[focus, isFocused, isSidePanelHiddenOrLargeScreen],
714+
[focus, isFocused, isSidePanelHiddenOrLargeScreen, handleSidePanelFocus],
701715
);
702716

703717
/**
@@ -797,6 +811,11 @@ function ComposerWithSuggestions({
797811
return;
798812
}
799813

814+
// Do not focus side panels composer if it wasn't focused before
815+
if (isInSidePanel && !ReportActionComposeFocusManager.sidePanelComposerRef.current) {
816+
return;
817+
}
818+
800819
// Do not focus the composer if the Side Panel is visible
801820
if (!isSidePanelHiddenOrLargeScreen) {
802821
return;
@@ -814,7 +833,7 @@ function ComposerWithSuggestions({
814833
return;
815834
}
816835
focus(true);
817-
}, [focus, prevIsFocused, editFocused, prevIsModalVisible, isFocused, modal?.isVisible, isNextModalWillOpenRef, shouldAutoFocus, isSidePanelHiddenOrLargeScreen]);
836+
}, [focus, prevIsFocused, editFocused, prevIsModalVisible, isFocused, modal?.isVisible, isNextModalWillOpenRef, shouldAutoFocus, isSidePanelHiddenOrLargeScreen, isInSidePanel]);
818837

819838
useEffect(() => {
820839
// 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({
913932
);
914933

915934
const handleFocus = useCallback(() => {
916-
// The last composer that had focus should re-gain focus
917-
setUpComposeFocusManager(true);
935+
handleSidePanelFocus();
936+
setUpComposeFocusManager(!isInSidePanel);
918937
onFocus();
919-
}, [onFocus, setUpComposeFocusManager]);
938+
}, [onFocus, setUpComposeFocusManager, handleSidePanelFocus, isInSidePanel]);
920939

921940
// When using the suggestions box (Suggestions) we need to imperatively
922941
// set the cursor to the end of the suggestion/mention after it's selected.

0 commit comments

Comments
 (0)