From e63344c9915697935f6152d2cf52b8d70c3d00f0 Mon Sep 17 00:00:00 2001 From: VH Date: Thu, 13 Jul 2023 16:42:01 +0700 Subject: [PATCH 1/5] Hide EmojiPicker when screen change size and emojiPopoverAnchor is null --- src/components/EmojiPicker/EmojiPicker.js | 40 +++++++++++-------- .../EmojiPicker/EmojiPickerButton.js | 3 +- src/components/Reactions/AddReactionBubble.js | 3 +- .../Reactions/MiniQuickEmojiReactions.js | 3 +- src/libs/actions/EmojiPickerAction.js | 9 ++++- 5 files changed, 38 insertions(+), 20 deletions(-) diff --git a/src/components/EmojiPicker/EmojiPicker.js b/src/components/EmojiPicker/EmojiPicker.js index 1eb4b5a5c496..4c64c5b0e31b 100644 --- a/src/components/EmojiPicker/EmojiPicker.js +++ b/src/components/EmojiPicker/EmojiPicker.js @@ -34,21 +34,6 @@ const EmojiPicker = forwardRef((props, ref) => { const onEmojiSelected = useRef(() => {}); const emojiSearchInput = useRef(); - useEffect(() => { - if (isEmojiPickerVisible) { - Keyboard.dismiss(); - } - - const emojiPopoverDimensionListener = Dimensions.addEventListener('change', () => { - calculateAnchorPosition(emojiPopoverAnchor.current).then((value) => { - setEmojiPopoverAnchorPosition(value); - }); - }); - return () => { - emojiPopoverDimensionListener.remove(); - }; - }, [isEmojiPickerVisible]); - /** * Show the emoji picker menu. * @@ -130,7 +115,30 @@ const EmojiPicker = forwardRef((props, ref) => { */ const isActiveReportAction = (actionID) => Boolean(actionID) && reportAction.reportActionID === actionID; - useImperativeHandle(ref, () => ({showEmojiPicker, isActiveReportAction, hideEmojiPicker, isEmojiPickerVisible})); + const resetEmojiPopoverAnchor = () => emojiPopoverAnchor.current = null; + + useImperativeHandle(ref, () => ({showEmojiPicker, isActiveReportAction, hideEmojiPicker, isEmojiPickerVisible, resetEmojiPopoverAnchor})); + + useEffect(() => { + if (isEmojiPickerVisible) { + Keyboard.dismiss(); + } + + const emojiPopoverDimensionListener = Dimensions.addEventListener('change', () => { + if (!emojiPopoverAnchor.current) { + if (isEmojiPickerVisible) { + hideEmojiPicker(); + } + return; + } + calculateAnchorPosition(emojiPopoverAnchor.current).then((value) => { + setEmojiPopoverAnchorPosition(value); + }); + }); + return () => { + emojiPopoverDimensionListener.remove(); + }; + }, [isEmojiPickerVisible]); // There is no way to disable animations, and they are really laggy, because there are so many // emojis. The best alternative is to set it to 1ms so it just "pops" in and out diff --git a/src/components/EmojiPicker/EmojiPickerButton.js b/src/components/EmojiPicker/EmojiPickerButton.js index 47dc93ac138a..ec2f0752e5f6 100644 --- a/src/components/EmojiPicker/EmojiPickerButton.js +++ b/src/components/EmojiPicker/EmojiPickerButton.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import PropTypes from 'prop-types'; import styles from '../../styles/styles'; import * as StyleUtils from '../../styles/StyleUtils'; @@ -27,6 +27,7 @@ const defaultProps = { function EmojiPickerButton(props) { let emojiPopoverAnchor = null; + useEffect(() => EmojiPickerAction.resetEmojiPopoverAnchor, []); return ( EmojiPickerAction.resetEmojiPopoverAnchor, []); const onPress = () => { const openPicker = (refParam, anchorOrigin) => { diff --git a/src/components/Reactions/MiniQuickEmojiReactions.js b/src/components/Reactions/MiniQuickEmojiReactions.js index 9973c5fae083..2b4d23ef66fd 100644 --- a/src/components/Reactions/MiniQuickEmojiReactions.js +++ b/src/components/Reactions/MiniQuickEmojiReactions.js @@ -1,4 +1,4 @@ -import React, {useRef} from 'react'; +import React, {useRef, useEffect} from 'react'; import {View} from 'react-native'; import _ from 'underscore'; import {withOnyx} from 'react-native-onyx'; @@ -55,6 +55,7 @@ const defaultProps = { */ function MiniQuickEmojiReactions(props) { const ref = useRef(); + useEffect(() => EmojiPickerAction.resetEmojiPopoverAnchor, []); const openEmojiPicker = () => { props.onPressOpenPicker(); diff --git a/src/libs/actions/EmojiPickerAction.js b/src/libs/actions/EmojiPickerAction.js index 458154913e3c..de462ac283f3 100644 --- a/src/libs/actions/EmojiPickerAction.js +++ b/src/libs/actions/EmojiPickerAction.js @@ -52,4 +52,11 @@ function isEmojiPickerVisible() { return emojiPickerRef.current.isEmojiPickerVisible; } -export {emojiPickerRef, showEmojiPicker, hideEmojiPicker, isActiveReportAction, isEmojiPickerVisible}; +function resetEmojiPopoverAnchor() { + if (!emojiPickerRef.current) { + return; + } + return emojiPickerRef.current.resetEmojiPopoverAnchor(); +} + +export {emojiPickerRef, showEmojiPicker, hideEmojiPicker, isActiveReportAction, isEmojiPickerVisible, resetEmojiPopoverAnchor}; From bfed0b3a8176fd0489c653807acaeff962230789 Mon Sep 17 00:00:00 2001 From: VH Date: Thu, 13 Jul 2023 17:15:37 +0700 Subject: [PATCH 2/5] Fix linter --- src/components/EmojiPicker/EmojiPicker.js | 2 +- src/components/EmojiPicker/EmojiPickerButton.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/EmojiPicker/EmojiPicker.js b/src/components/EmojiPicker/EmojiPicker.js index 4c64c5b0e31b..91055a122ed9 100644 --- a/src/components/EmojiPicker/EmojiPicker.js +++ b/src/components/EmojiPicker/EmojiPicker.js @@ -115,7 +115,7 @@ const EmojiPicker = forwardRef((props, ref) => { */ const isActiveReportAction = (actionID) => Boolean(actionID) && reportAction.reportActionID === actionID; - const resetEmojiPopoverAnchor = () => emojiPopoverAnchor.current = null; + const resetEmojiPopoverAnchor = () => (emojiPopoverAnchor.current = null); useImperativeHandle(ref, () => ({showEmojiPicker, isActiveReportAction, hideEmojiPicker, isEmojiPickerVisible, resetEmojiPopoverAnchor})); diff --git a/src/components/EmojiPicker/EmojiPickerButton.js b/src/components/EmojiPicker/EmojiPickerButton.js index ec2f0752e5f6..a90439a46f69 100644 --- a/src/components/EmojiPicker/EmojiPickerButton.js +++ b/src/components/EmojiPicker/EmojiPickerButton.js @@ -1,4 +1,4 @@ -import React, { useEffect } from 'react'; +import React, {useEffect} from 'react'; import PropTypes from 'prop-types'; import styles from '../../styles/styles'; import * as StyleUtils from '../../styles/StyleUtils'; From 1aa79ab9d690f4fab79eb5257e4fff11f62f54ec Mon Sep 17 00:00:00 2001 From: VH Date: Thu, 13 Jul 2023 18:38:09 +0700 Subject: [PATCH 3/5] Avoid hide emoji picker when open context menu on small screen devices --- src/components/EmojiPicker/EmojiPicker.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/EmojiPicker/EmojiPicker.js b/src/components/EmojiPicker/EmojiPicker.js index 91055a122ed9..1b70af19a917 100644 --- a/src/components/EmojiPicker/EmojiPicker.js +++ b/src/components/EmojiPicker/EmojiPicker.js @@ -126,7 +126,8 @@ const EmojiPicker = forwardRef((props, ref) => { const emojiPopoverDimensionListener = Dimensions.addEventListener('change', () => { if (!emojiPopoverAnchor.current) { - if (isEmojiPickerVisible) { + // In small screen width, the window size change might be due to keyboard open/hide, we should avoid hide EmojiPicker in those cases + if (isEmojiPickerVisible && !props.isSmallScreenWidth) { hideEmojiPicker(); } return; @@ -138,7 +139,7 @@ const EmojiPicker = forwardRef((props, ref) => { return () => { emojiPopoverDimensionListener.remove(); }; - }, [isEmojiPickerVisible]); + }, [isEmojiPickerVisible, props.isSmallScreenWidth]); // There is no way to disable animations, and they are really laggy, because there are so many // emojis. The best alternative is to set it to 1ms so it just "pops" in and out From bdaa5912149a482139cdfa60c197e1018c3d1772 Mon Sep 17 00:00:00 2001 From: VH Date: Sun, 23 Jul 2023 22:18:42 +0700 Subject: [PATCH 4/5] Revert change on MiniQuickEmojiReactions --- src/components/Reactions/MiniQuickEmojiReactions.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/Reactions/MiniQuickEmojiReactions.js b/src/components/Reactions/MiniQuickEmojiReactions.js index 2b4d23ef66fd..9973c5fae083 100644 --- a/src/components/Reactions/MiniQuickEmojiReactions.js +++ b/src/components/Reactions/MiniQuickEmojiReactions.js @@ -1,4 +1,4 @@ -import React, {useRef, useEffect} from 'react'; +import React, {useRef} from 'react'; import {View} from 'react-native'; import _ from 'underscore'; import {withOnyx} from 'react-native-onyx'; @@ -55,7 +55,6 @@ const defaultProps = { */ function MiniQuickEmojiReactions(props) { const ref = useRef(); - useEffect(() => EmojiPickerAction.resetEmojiPopoverAnchor, []); const openEmojiPicker = () => { props.onPressOpenPicker(); From a31de93c944b035227d09ffff9bbab2249279096 Mon Sep 17 00:00:00 2001 From: VH Date: Sun, 23 Jul 2023 22:25:22 +0700 Subject: [PATCH 5/5] Change to use visible state because the popoverAnchor will be reset when unmount --- src/components/EmojiPicker/EmojiPicker.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/EmojiPicker/EmojiPicker.js b/src/components/EmojiPicker/EmojiPicker.js index 1b70af19a917..285e0a6f4b8c 100644 --- a/src/components/EmojiPicker/EmojiPicker.js +++ b/src/components/EmojiPicker/EmojiPicker.js @@ -95,9 +95,7 @@ const EmojiPicker = forwardRef((props, ref) => { const selectEmoji = (emoji, emojiObject) => { // Prevent fast click / multiple emoji selection; // The first click will hide the emoji picker by calling the hideEmojiPicker() function - // and in that function the emojiPopoverAnchor ref to will be set to null (synchronously) - // thus we rely on that prop to prevent fast click / multiple emoji selection - if (!emojiPopoverAnchor.current) { + if (!isEmojiPickerVisible) { return; }