Skip to content

Commit

Permalink
Merge pull request #54858 from bernhardoj/fix/54599-can't-open-emoji-…
Browse files Browse the repository at this point in the history
…picker

Fix can't open emoji picker when edit composer is focused
  • Loading branch information
techievivek authored Jan 17, 2025
2 parents f2d2ebd + 542d1f4 commit 5a3d556
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 38 deletions.
11 changes: 1 addition & 10 deletions src/components/Reactions/QuickEmojiReactions/index.native.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,10 @@
import React from 'react';
import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManager';
import BaseQuickEmojiReactions from './BaseQuickEmojiReactions';
import type {OpenPickerCallback, QuickEmojiReactionsProps} from './types';

function QuickEmojiReactions({closeContextMenu, ...rest}: QuickEmojiReactionsProps) {
const onPressOpenPicker = (openPicker?: OpenPickerCallback) => {
// We first need to close the menu as it's a popover.
// The picker is a popover as well and on mobile there can only
// be one active popover at a time.
closeContextMenu(() => {
// As the menu which includes the button to open the emoji picker
// gets closed, before the picker actually opens, we pass the composer
// ref as anchor for the emoji picker popover.
openPicker?.(ReportActionComposeFocusManager.composerRef);
});
openPicker?.();
};

return (
Expand Down
56 changes: 28 additions & 28 deletions src/pages/home/report/ReportActionItemMessageEdit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,23 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import * as ComposerUtils from '@libs/ComposerUtils';
import {setShouldShowComposeInput} from '@libs/actions/Composer';
import {clearActive, isActive as isEmojiPickerActive, isEmojiPickerVisible} from '@libs/actions/EmojiPickerAction';
import {composerFocusKeepFocusOn, callback as inputFocusCallback, inputFocusChange} from '@libs/actions/InputFocus';
import {deleteReportActionDraft, editReportComment, saveReportActionDraft} from '@libs/actions/Report';
import {canSkipTriggerHotkeys, insertText} from '@libs/ComposerUtils';
import DomUtils from '@libs/DomUtils';
import * as EmojiUtils from '@libs/EmojiUtils';
import {extractEmojis, replaceAndExtractEmojis} from '@libs/EmojiUtils';
import focusComposerWithDelay from '@libs/focusComposerWithDelay';
import type {Selection} from '@libs/focusComposerWithDelay/types';
import focusEditAfterCancelDelete from '@libs/focusEditAfterCancelDelete';
import onyxSubscribe from '@libs/onyxSubscribe';
import Parser from '@libs/Parser';
import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManager';
import reportActionItemEventHandler from '@libs/ReportActionItemEventHandler';
import * as ReportActionsUtils from '@libs/ReportActionsUtils';
import * as ReportUtils from '@libs/ReportUtils';
import {getReportActionHtml, isDeletedAction} from '@libs/ReportActionsUtils';
import {getCommentLength} from '@libs/ReportUtils';
import setShouldShowComposeInputKeyboardAware from '@libs/setShouldShowComposeInputKeyboardAware';
import * as ComposerActions from '@userActions/Composer';
import * as EmojiPickerAction from '@userActions/EmojiPickerAction';
import * as InputFocus from '@userActions/InputFocus';
import * as Report from '@userActions/Report';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type * as OnyxTypes from '@src/types/onyx';
Expand Down Expand Up @@ -102,7 +102,7 @@ function ReportActionItemMessageEdit(
const emojisPresentBefore = useRef<Emoji[]>([]);
const [draft, setDraft] = useState(() => {
if (draftMessage) {
emojisPresentBefore.current = EmojiUtils.extractEmojis(draftMessage);
emojisPresentBefore.current = extractEmojis(draftMessage);
}
return draftMessage;
});
Expand All @@ -126,17 +126,17 @@ function ReportActionItemMessageEdit(
useEffect(() => {
draftMessageVideoAttributeCache.clear();

const originalMessage = Parser.htmlToMarkdown(ReportActionsUtils.getReportActionHtml(action), {
const originalMessage = Parser.htmlToMarkdown(getReportActionHtml(action), {
cacheVideoAttributes: (videoSource, attrs) => draftMessageVideoAttributeCache.set(videoSource, attrs),
});
if (ReportActionsUtils.isDeletedAction(action) || !!(action.message && draftMessage === originalMessage) || !!(prevDraftMessage === draftMessage || isCommentPendingSaved.current)) {
if (isDeletedAction(action) || !!(action.message && draftMessage === originalMessage) || !!(prevDraftMessage === draftMessage || isCommentPendingSaved.current)) {
return;
}
setDraft(draftMessage);
}, [draftMessage, action, prevDraftMessage]);

useEffect(() => {
InputFocus.composerFocusKeepFocusOn(textInputRef.current as HTMLElement, isFocused, modal, onyxFocused);
composerFocusKeepFocusOn(textInputRef.current as HTMLElement, isFocused, modal, onyxFocused);
}, [isFocused, modal, onyxFocused]);

useEffect(() => {
Expand Down Expand Up @@ -183,7 +183,7 @@ function ReportActionItemMessageEdit(

// 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(action.reportActionID) || ReportActionContextMenu.isActiveReportAction(action.reportActionID),
() => isFocusedRef.current || isEmojiPickerActive(action.reportActionID) || ReportActionContextMenu.isActiveReportAction(action.reportActionID),
[action.reportActionID],
);

Expand All @@ -210,16 +210,16 @@ function ReportActionItemMessageEdit(
}

return () => {
InputFocus.callback(() => setIsFocused(false));
InputFocus.inputFocusChange(false);
inputFocusCallback(() => setIsFocused(false));
inputFocusChange(false);

// Skip if the current report action is not active
if (!isActive()) {
return;
}

if (EmojiPickerAction.isActive(action.reportActionID)) {
EmojiPickerAction.clearActive();
if (isEmojiPickerActive(action.reportActionID)) {
clearActive();
}
if (ReportActionContextMenu.isActiveReportAction(action.reportActionID)) {
ReportActionContextMenu.clearActiveReportAction();
Expand All @@ -235,7 +235,7 @@ function ReportActionItemMessageEdit(
);

// show the composer after editing is complete for devices that hide the composer during editing.
useEffect(() => () => ComposerActions.setShouldShowComposeInput(true), []);
useEffect(() => () => setShouldShowComposeInput(true), []);

/**
* Save the draft of the comment. This debounced so that we're not ceaselessly saving your edit. Saving the draft
Expand All @@ -246,7 +246,7 @@ function ReportActionItemMessageEdit(
() =>
// eslint-disable-next-line react-compiler/react-compiler
lodashDebounce((newDraft: string) => {
Report.saveReportActionDraft(reportID, action, newDraft);
saveReportActionDraft(reportID, action, newDraft);
isCommentPendingSaved.current = false;
}, 1000),
[reportID, action],
Expand All @@ -267,7 +267,7 @@ function ReportActionItemMessageEdit(
*/
const updateDraft = useCallback(
(newDraftInput: string) => {
const {text: newDraft, emojis, cursorPosition} = EmojiUtils.replaceAndExtractEmojis(newDraftInput, preferredSkinTone, preferredLocale);
const {text: newDraft, emojis, cursorPosition} = replaceAndExtractEmojis(newDraftInput, preferredSkinTone, preferredLocale);

emojisPresentBefore.current = emojis;

Expand Down Expand Up @@ -301,7 +301,7 @@ function ReportActionItemMessageEdit(
* Delete the draft of the comment being edited. This will take the comment out of "edit mode" with the old content.
*/
const deleteDraft = useCallback(() => {
Report.deleteReportActionDraft(reportID, action);
deleteReportActionDraft(reportID, action);

if (isActive()) {
ReportActionComposeFocusManager.clear(true);
Expand All @@ -324,7 +324,7 @@ function ReportActionItemMessageEdit(
*/
const publishDraft = useCallback(() => {
// Do nothing if draft exceed the character limit
if (ReportUtils.getCommentLength(draft, {reportID}) > CONST.MAX_COMMENT_LENGTH) {
if (getCommentLength(draft, {reportID}) > CONST.MAX_COMMENT_LENGTH) {
return;
}

Expand All @@ -336,7 +336,7 @@ function ReportActionItemMessageEdit(
ReportActionContextMenu.showDeleteModal(reportID, action, true, deleteDraft, () => focusEditAfterCancelDelete(textInputRef.current));
return;
}
Report.editReportComment(reportID, action, trimmedNewDraft, Object.fromEntries(draftMessageVideoAttributeCache));
editReportComment(reportID, action, trimmedNewDraft, Object.fromEntries(draftMessageVideoAttributeCache));
deleteDraft();
}, [action, deleteDraft, draft, reportID]);

Expand All @@ -357,7 +357,7 @@ function ReportActionItemMessageEdit(
// To fix this, immediately set the selection again after focusing the input.
emojiPickerSelectionRef.current = newSelection;
}
updateDraft(ComposerUtils.insertText(draft, selection, `${emoji} `));
updateDraft(insertText(draft, selection, `${emoji} `));
};

const hideSuggestionMenu = useCallback(() => {
Expand All @@ -382,7 +382,7 @@ function ReportActionItemMessageEdit(
*/
const triggerSaveOrCancel = useCallback(
(e: NativeSyntheticEvent<TextInputKeyPressEventData> | KeyboardEvent) => {
if (!e || ComposerUtils.canSkipTriggerHotkeys(shouldUseNarrowLayout, isKeyboardShown)) {
if (!e || canSkipTriggerHotkeys(shouldUseNarrowLayout, isKeyboardShown)) {
return;
}
const keyEvent = e as KeyboardEvent;
Expand Down Expand Up @@ -535,8 +535,8 @@ function ReportActionItemMessageEdit(
setUpComposeFocusManager();

// Clear active report action when another action gets focused
if (!EmojiPickerAction.isActive(action.reportActionID)) {
EmojiPickerAction.clearActive();
if (!isEmojiPickerActive(action.reportActionID)) {
clearActive();
}
if (!ReportActionContextMenu.isActiveReportAction(action.reportActionID)) {
ReportActionContextMenu.clearActiveReportAction();
Expand All @@ -545,7 +545,7 @@ function ReportActionItemMessageEdit(
onBlur={(event: NativeSyntheticEvent<TextInputFocusEventData>) => {
setIsFocused(false);
const relatedTargetId = event.nativeEvent?.relatedTarget?.id;
if (relatedTargetId === CONST.COMPOSER.NATIVE_ID || relatedTargetId === CONST.EMOJI_PICKER_BUTTON_NATIVE_ID || EmojiPickerAction.isEmojiPickerVisible()) {
if (relatedTargetId === CONST.COMPOSER.NATIVE_ID || relatedTargetId === CONST.EMOJI_PICKER_BUTTON_NATIVE_ID || isEmojiPickerVisible()) {
return;
}
setShouldShowComposeInputKeyboardAware(true);
Expand Down

0 comments on commit 5a3d556

Please sign in to comment.