From 05b7bcdedbcc4064f81d18a37dcc3dc22cb99cc7 Mon Sep 17 00:00:00 2001 From: ntdiary <2471314@gmail.com> Date: Fri, 21 Apr 2023 23:18:14 +0800 Subject: [PATCH 1/8] prevent focus event when long press in emoji suggestion component --- src/components/EmojiSuggestions.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/components/EmojiSuggestions.js b/src/components/EmojiSuggestions.js index 24f0203b7577..6af44ab61c14 100644 --- a/src/components/EmojiSuggestions.js +++ b/src/components/EmojiSuggestions.js @@ -113,8 +113,19 @@ const EmojiSuggestions = (props) => { props.isEmojiPickerLarge, ); + const containerRef = React.useRef(null); + React.useEffect(() => { + const container = containerRef.current; + if (!container) { + return; + } + container.onpointerdown = e => e.preventDefault(); + return () => container.onpointerdown = null; + }, []); + return ( Date: Mon, 24 Apr 2023 23:51:25 +0800 Subject: [PATCH 2/8] do nothing when long press on emoji suggestions. --- src/components/EmojiSuggestions.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/components/EmojiSuggestions.js b/src/components/EmojiSuggestions.js index 6af44ab61c14..b4b9c6796a37 100644 --- a/src/components/EmojiSuggestions.js +++ b/src/components/EmojiSuggestions.js @@ -11,6 +11,7 @@ import * as EmojiUtils from '../libs/EmojiUtils'; import Text from './Text'; import CONST from '../CONST'; import getStyledTextArray from '../libs/GetStyledTextArray'; +import * as DeviceCapabilities from '../libs/DeviceCapabilities'; const propTypes = { /** The index of the highlighted emoji */ @@ -91,6 +92,7 @@ const EmojiSuggestions = (props) => { )} onMouseDown={e => e.preventDefault()} onPress={() => props.onSelect(index)} + onLongPress={() => {}} > {EmojiUtils.getEmojiCodeWithSkinColor(item, props.preferredSkinToneIndex)} @@ -119,7 +121,12 @@ const EmojiSuggestions = (props) => { if (!container) { return; } - container.onpointerdown = e => e.preventDefault(); + container.onpointerdown = (e) => { + if (DeviceCapabilities.hasHoverSupport()) { + return; + } + e.preventDefault(); + }; return () => container.onpointerdown = null; }, []); From bd68abb5ccc3905f55797842b836e8a0f367b551 Mon Sep 17 00:00:00 2001 From: ntdiary <2471314@gmail.com> Date: Tue, 25 Apr 2023 16:03:02 +0800 Subject: [PATCH 3/8] rename to platform-specific file --- .../BaseEmojiSuggestions.js} | 80 ++++--------------- .../emojiSuggestionsPropTypes.js | 42 ++++++++++ src/components/EmojiSuggestions/index.js | 32 ++++++++ .../EmojiSuggestions/index.native.js | 14 ++++ 4 files changed, 104 insertions(+), 64 deletions(-) rename src/components/{EmojiSuggestions.js => EmojiSuggestions/BaseEmojiSuggestions.js} (59%) create mode 100644 src/components/EmojiSuggestions/emojiSuggestionsPropTypes.js create mode 100644 src/components/EmojiSuggestions/index.js create mode 100644 src/components/EmojiSuggestions/index.native.js diff --git a/src/components/EmojiSuggestions.js b/src/components/EmojiSuggestions/BaseEmojiSuggestions.js similarity index 59% rename from src/components/EmojiSuggestions.js rename to src/components/EmojiSuggestions/BaseEmojiSuggestions.js index b4b9c6796a37..6491b2c0d085 100644 --- a/src/components/EmojiSuggestions.js +++ b/src/components/EmojiSuggestions/BaseEmojiSuggestions.js @@ -1,52 +1,16 @@ import React from 'react'; import {View, Pressable} from 'react-native'; -import PropTypes from 'prop-types'; import _ from 'underscore'; // We take FlatList from this package to properly handle the scrolling of EmojiSuggestions in chats since one scroll is nested inside another import {FlatList} from 'react-native-gesture-handler'; -import styles from '../styles/styles'; -import * as StyleUtils from '../styles/StyleUtils'; -import * as EmojiUtils from '../libs/EmojiUtils'; -import Text from './Text'; -import CONST from '../CONST'; -import getStyledTextArray from '../libs/GetStyledTextArray'; -import * as DeviceCapabilities from '../libs/DeviceCapabilities'; - -const propTypes = { - /** The index of the highlighted emoji */ - highlightedEmojiIndex: PropTypes.number, - - /** Array of suggested emoji */ - emojis: PropTypes.arrayOf(PropTypes.shape({ - /** The emoji code */ - code: PropTypes.string, - - /** The name of the emoji */ - name: PropTypes.string, - })).isRequired, - - /** Fired when the user selects an emoji */ - onSelect: PropTypes.func.isRequired, - - /** Emoji prefix that follows the colon */ - prefix: PropTypes.string.isRequired, - - /** Show that we can use large emoji picker. - * Depending on available space and whether the input is expanded, we can have a small or large emoji suggester. - * When this value is false, the suggester will have a height of 2.5 items. When this value is true, the height can be up to 5 items. */ - isEmojiPickerLarge: PropTypes.bool.isRequired, - - /** Show that we should include ReportRecipientLocalTime view height */ - shouldIncludeReportRecipientLocalTimeHeight: PropTypes.bool.isRequired, - - /** Stores user's preferred skin tone */ - preferredSkinToneIndex: PropTypes.number.isRequired, -}; - -const defaultProps = { - highlightedEmojiIndex: 0, -}; +import styles from '../../styles/styles'; +import * as StyleUtils from '../../styles/StyleUtils'; +import * as EmojiUtils from '../../libs/EmojiUtils'; +import Text from '../Text'; +import CONST from '../../CONST'; +import getStyledTextArray from '../../libs/GetStyledTextArray'; +import {propTypes, defaultProps} from './emojiSuggestionsPropTypes'; /** * @param {Number} numRows @@ -72,7 +36,7 @@ const measureHeightOfEmojiRows = (numRows, isEmojiPickerLarge) => { */ const keyExtractor = (item, index) => `${item.name}+${index}}`; -const EmojiSuggestions = (props) => { +const BaseEmojiSuggestions = (props) => { /** * Render a suggestion menu item component. * @param {Object} params.item @@ -115,24 +79,9 @@ const EmojiSuggestions = (props) => { props.isEmojiPickerLarge, ); - const containerRef = React.useRef(null); - React.useEffect(() => { - const container = containerRef.current; - if (!container) { - return; - } - container.onpointerdown = (e) => { - if (DeviceCapabilities.hasHoverSupport()) { - return; - } - e.preventDefault(); - }; - return () => container.onpointerdown = null; - }, []); - return ( { ); }; -EmojiSuggestions.propTypes = propTypes; -EmojiSuggestions.defaultProps = defaultProps; -EmojiSuggestions.displayName = 'EmojiSuggestions'; +BaseEmojiSuggestions.propTypes = propTypes; +BaseEmojiSuggestions.defaultProps = defaultProps; +BaseEmojiSuggestions.displayName = 'BaseEmojiSuggestions'; -export default EmojiSuggestions; +export default React.forwardRef((props, ref) => ( + // eslint-disable-next-line react/jsx-props-no-spreading + +)); diff --git a/src/components/EmojiSuggestions/emojiSuggestionsPropTypes.js b/src/components/EmojiSuggestions/emojiSuggestionsPropTypes.js new file mode 100644 index 000000000000..a6ded0f927f7 --- /dev/null +++ b/src/components/EmojiSuggestions/emojiSuggestionsPropTypes.js @@ -0,0 +1,42 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +const propTypes = { + /** The index of the highlighted emoji */ + highlightedEmojiIndex: PropTypes.number, + + /** Array of suggested emoji */ + emojis: PropTypes.arrayOf(PropTypes.shape({ + /** The emoji code */ + code: PropTypes.string, + + /** The name of the emoji */ + name: PropTypes.string, + })).isRequired, + + /** Fired when the user selects an emoji */ + onSelect: PropTypes.func.isRequired, + + /** Emoji prefix that follows the colon */ + prefix: PropTypes.string.isRequired, + + /** Show that we can use large emoji picker. + * Depending on available space and whether the input is expanded, we can have a small or large emoji suggester. + * When this value is false, the suggester will have a height of 2.5 items. When this value is true, the height can be up to 5 items. */ + isEmojiPickerLarge: PropTypes.bool.isRequired, + + /** Show that we should include ReportRecipientLocalTime view height */ + shouldIncludeReportRecipientLocalTimeHeight: PropTypes.bool.isRequired, + + /** Stores user's preferred skin tone */ + preferredSkinToneIndex: PropTypes.number.isRequired, + + /** A ref to forward to the suggestion container */ + forwardedRef: PropTypes.shape({current: PropTypes.instanceOf(React.Component)}), +}; + +const defaultProps = { + highlightedEmojiIndex: 0, +}; + +export {propTypes, defaultProps}; diff --git a/src/components/EmojiSuggestions/index.js b/src/components/EmojiSuggestions/index.js new file mode 100644 index 000000000000..e245d9d11f0f --- /dev/null +++ b/src/components/EmojiSuggestions/index.js @@ -0,0 +1,32 @@ +import React from 'react'; +import BaseEmojiSuggestions from './BaseEmojiSuggestions'; +import * as DeviceCapabilities from '../../libs/DeviceCapabilities'; +import {propTypes, defaultProps} from './emojiSuggestionsPropTypes'; + +const EmojiSuggestions = (props) => { + const containerRef = React.useRef(null); + React.useEffect(() => { + const container = containerRef.current; + if (!container) { + return; + } + container.onpointerdown = (e) => { + if (DeviceCapabilities.hasHoverSupport()) { + return; + } + e.preventDefault(); + }; + return () => container.onpointerdown = null; + }, []); + + return ( + // eslint-disable-next-line react/jsx-props-no-spreading + + ); +}; + +EmojiSuggestions.propTypes = propTypes; +EmojiSuggestions.defaultProps = defaultProps; +EmojiSuggestions.displayName = 'EmojiSuggestions'; + +export default EmojiSuggestions; diff --git a/src/components/EmojiSuggestions/index.native.js b/src/components/EmojiSuggestions/index.native.js new file mode 100644 index 000000000000..30cc58b8c675 --- /dev/null +++ b/src/components/EmojiSuggestions/index.native.js @@ -0,0 +1,14 @@ +import React from 'react'; +import BaseEmojiSuggestions from './BaseEmojiSuggestions'; +import {propTypes, defaultProps} from './emojiSuggestionsPropTypes'; + +const EmojiSuggestions = props => ( + // eslint-disable-next-line react/jsx-props-no-spreading + +); + +EmojiSuggestions.propTypes = propTypes; +EmojiSuggestions.defaultProps = defaultProps; +EmojiSuggestions.displayName = 'EmojiSuggestions'; + +export default EmojiSuggestions; From 65c466ea8660771171d136a75f9bc7514ebe0a98 Mon Sep 17 00:00:00 2001 From: ntdiary <2471314@gmail.com> Date: Tue, 25 Apr 2023 16:20:41 +0800 Subject: [PATCH 4/8] change forwardedRef prop type --- src/components/EmojiSuggestions/emojiSuggestionsPropTypes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/EmojiSuggestions/emojiSuggestionsPropTypes.js b/src/components/EmojiSuggestions/emojiSuggestionsPropTypes.js index a6ded0f927f7..8b1bfcd322d7 100644 --- a/src/components/EmojiSuggestions/emojiSuggestionsPropTypes.js +++ b/src/components/EmojiSuggestions/emojiSuggestionsPropTypes.js @@ -32,7 +32,7 @@ const propTypes = { preferredSkinToneIndex: PropTypes.number.isRequired, /** A ref to forward to the suggestion container */ - forwardedRef: PropTypes.shape({current: PropTypes.instanceOf(React.Component)}), + forwardedRef: PropTypes.object, }; const defaultProps = { From 7958b749d65b3491fbde541a7240f6d35729388d Mon Sep 17 00:00:00 2001 From: ntdiary <2471314@gmail.com> Date: Tue, 25 Apr 2023 16:56:42 +0800 Subject: [PATCH 5/8] remove unused import --- src/components/EmojiSuggestions/emojiSuggestionsPropTypes.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/EmojiSuggestions/emojiSuggestionsPropTypes.js b/src/components/EmojiSuggestions/emojiSuggestionsPropTypes.js index 8b1bfcd322d7..58344bc00d78 100644 --- a/src/components/EmojiSuggestions/emojiSuggestionsPropTypes.js +++ b/src/components/EmojiSuggestions/emojiSuggestionsPropTypes.js @@ -1,4 +1,3 @@ -import React from 'react'; import PropTypes from 'prop-types'; const propTypes = { From d8a046808f829d557233fa849146b5735a220275 Mon Sep 17 00:00:00 2001 From: ntdiary <2471314@gmail.com> Date: Wed, 26 Apr 2023 20:38:54 +0800 Subject: [PATCH 6/8] Add the description to explain why there are platform specific file --- src/components/EmojiSuggestions/index.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/components/EmojiSuggestions/index.js b/src/components/EmojiSuggestions/index.js index e245d9d11f0f..daf8fea7bebb 100644 --- a/src/components/EmojiSuggestions/index.js +++ b/src/components/EmojiSuggestions/index.js @@ -3,6 +3,11 @@ import BaseEmojiSuggestions from './BaseEmojiSuggestions'; import * as DeviceCapabilities from '../../libs/DeviceCapabilities'; import {propTypes, defaultProps} from './emojiSuggestionsPropTypes'; +/** + * On the web platform, when tapping on emoji suggestions, we need to prevent focus shifting to avoid blurring the main input. + * On the native platform, tapping on emoji suggestions will not blur the main input. + */ + const EmojiSuggestions = (props) => { const containerRef = React.useRef(null); React.useEffect(() => { From 2e8f5cee652d6d759c7a0922320acddce2a99ea1 Mon Sep 17 00:00:00 2001 From: ntdiary Date: Wed, 26 Apr 2023 22:21:20 +0800 Subject: [PATCH 7/8] Update src/components/EmojiSuggestions/index.js Co-authored-by: Tim Golen --- src/components/EmojiSuggestions/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/EmojiSuggestions/index.js b/src/components/EmojiSuggestions/index.js index daf8fea7bebb..eead9a1accf7 100644 --- a/src/components/EmojiSuggestions/index.js +++ b/src/components/EmojiSuggestions/index.js @@ -4,7 +4,7 @@ import * as DeviceCapabilities from '../../libs/DeviceCapabilities'; import {propTypes, defaultProps} from './emojiSuggestionsPropTypes'; /** - * On the web platform, when tapping on emoji suggestions, we need to prevent focus shifting to avoid blurring the main input. + * On the mobile-web platform, when long-pressing on emoji suggestions, we need to prevent focus shifting to avoid blurring the main input which makes the emoji picker close and adds the emoji to the composer. The desired pattern for all platforms is to do nothing on long-press. * On the native platform, tapping on emoji suggestions will not blur the main input. */ From 384698c8486acbd6dee7db26fc951f8d0da0e2b8 Mon Sep 17 00:00:00 2001 From: ntdiary <2471314@gmail.com> Date: Wed, 26 Apr 2023 22:54:25 +0800 Subject: [PATCH 8/8] fix lint max-length error --- src/components/EmojiSuggestions/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/EmojiSuggestions/index.js b/src/components/EmojiSuggestions/index.js index eead9a1accf7..6a3b52f27dd9 100644 --- a/src/components/EmojiSuggestions/index.js +++ b/src/components/EmojiSuggestions/index.js @@ -4,7 +4,9 @@ import * as DeviceCapabilities from '../../libs/DeviceCapabilities'; import {propTypes, defaultProps} from './emojiSuggestionsPropTypes'; /** - * On the mobile-web platform, when long-pressing on emoji suggestions, we need to prevent focus shifting to avoid blurring the main input which makes the emoji picker close and adds the emoji to the composer. The desired pattern for all platforms is to do nothing on long-press. + * On the mobile-web platform, when long-pressing on emoji suggestions, + * we need to prevent focus shifting to avoid blurring the main input which makes the emoji picker close and adds the emoji to the composer. + * The desired pattern for all platforms is to do nothing on long-press. * On the native platform, tapping on emoji suggestions will not blur the main input. */