From 069d246cf9d6fbc1ac622b62884fac8d927ee1d8 Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Mon, 1 May 2023 12:48:28 +0200 Subject: [PATCH 01/21] handle paddings for EmojiPicker --- src/CONST.js | 4 ++++ src/components/EmojiPicker/EmojiPicker.js | 19 +++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/CONST.js b/src/CONST.js index 20e293011f1c..cd25b23fe358 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -712,6 +712,10 @@ const CONST = { WIDTH: 320, HEIGHT: 416, }, + CATEGORY_SHORTCUT_BAR_HEIGHT: 40, + SMALL_EMOJI_PICKER_SIZE: { + WIDTH: '100%', + }, NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT: 256, EMOJI_PICKER_ITEM_HEIGHT: 32, EMOJI_PICKER_HEADER_HEIGHT: 32, diff --git a/src/components/EmojiPicker/EmojiPicker.js b/src/components/EmojiPicker/EmojiPicker.js index 369365a8db84..c76d52ee6aff 100644 --- a/src/components/EmojiPicker/EmojiPicker.js +++ b/src/components/EmojiPicker/EmojiPicker.js @@ -4,12 +4,20 @@ import _ from 'underscore'; import EmojiPickerMenu from './EmojiPickerMenu'; import CONST from '../../CONST'; import PopoverWithMeasuredContent from '../PopoverWithMeasuredContent'; +import withWindowDimensions, {windowDimensionsPropTypes} from '../withWindowDimensions'; +import withViewportOffsetTop, {viewportOffsetTopPropTypes} from '../withViewportOffsetTop'; +import compose from '../../libs/compose'; const DEFAULT_ANCHOR_ORIGIN = { horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT, vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.BOTTOM, }; +const propTypes = { + ...windowDimensionsPropTypes, + ...viewportOffsetTopPropTypes, +}; + class EmojiPicker extends React.Component { constructor(props) { super(props); @@ -147,7 +155,8 @@ class EmojiPicker extends React.Component { * Focus the search input in the emoji picker. */ focusEmojiSearchInput() { - if (!this.emojiSearchInput) { + // we won't focus the input if it's mobile device + if (!this.emojiSearchInput || this.props.isSmallScreenWidth) { return; } this.emojiSearchInput.focus(); @@ -176,6 +185,7 @@ class EmojiPicker extends React.Component { }} anchorOrigin={this.state.emojiPopoverAnchorOrigin} measureContent={this.measureContent} + outerStyle={{maxHeight: this.props.windowHeight, marginTop: this.props.viewportOffsetTop}} > Date: Mon, 1 May 2023 12:50:13 +0200 Subject: [PATCH 02/21] add search input for native (mobile) --- .../EmojiPickerMenu/index.native.js | 108 +++++++++++++++--- src/styles/StyleUtils.js | 15 ++- src/styles/styles.js | 7 +- 3 files changed, 112 insertions(+), 18 deletions(-) diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.native.js b/src/components/EmojiPicker/EmojiPickerMenu/index.native.js index 702be109e5e1..72597ab6dd86 100644 --- a/src/components/EmojiPicker/EmojiPickerMenu/index.native.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/index.native.js @@ -16,7 +16,10 @@ import withLocalize, {withLocalizePropTypes} from '../../withLocalize'; import EmojiSkinToneList from '../EmojiSkinToneList'; import * as EmojiUtils from '../../../libs/EmojiUtils'; import * as User from '../../../libs/actions/User'; +import TextInput from '../../TextInput'; import CategoryShortcutBar from '../CategoryShortcutBar'; +import * as StyleUtils from '../../../styles/StyleUtils'; +import KeyboardSpacer from '../../KeyboardSpacer'; const propTypes = { /** Function to add the selected emoji to the main compose text input */ @@ -64,14 +67,48 @@ class EmojiPickerMenu extends Component { this.renderItem = this.renderItem.bind(this); this.isMobileLandscape = this.isMobileLandscape.bind(this); this.updatePreferredSkinTone = this.updatePreferredSkinTone.bind(this); + this.filterEmojis = _.debounce(this.filterEmojis.bind(this), 300); this.scrollToHeader = this.scrollToHeader.bind(this); this.getItemLayout = this.getItemLayout.bind(this); + + this.state = { + filteredEmojis: this.emojis, + headerIndices: this.headerRowIndices, + }; } getItemLayout(data, index) { return {length: CONST.EMOJI_PICKER_ITEM_HEIGHT, offset: CONST.EMOJI_PICKER_ITEM_HEIGHT * index, index}; } + /** + * Filter the entire list of emojis to only emojis that have the search term in their keywords + * + * @param {String} searchTerm + */ + filterEmojis(searchTerm) { + const normalizedSearchTerm = searchTerm.toLowerCase().trim().replaceAll(':', ''); + + if (this.emojiList) { + this.emojiList.scrollToOffset({offset: 0, animated: false}); + } + + if (normalizedSearchTerm === '') { + this.setState({ + filteredEmojis: this.emojis, + headerIndices: this.headerRowIndices, + }); + + return; + } + const newFilteredEmojiList = EmojiUtils.suggestEmojis(`:${normalizedSearchTerm}`, this.emojis.length); + + this.setState({ + filteredEmojis: newFilteredEmojiList, + headerIndices: undefined, + }); + } + /** * @param {String} emoji * @param {Object} emojiObject @@ -112,6 +149,16 @@ class EmojiPickerMenu extends Component { })(); } + /** + * Return a unique key for each emoji item + * + * @param {Object} item + * @returns {String} + */ + keyExtractor(item) { + return (`emoji_picker_${item.code}`); + } + /** * Given an emoji item object, render a component based on its type. * Items with the code "SPACER" return nothing and are used to fill rows up to 8 @@ -149,32 +196,61 @@ class EmojiPickerMenu extends Component { } render() { + const isFiltered = this.emojis.length !== this.state.filteredEmojis.length; return ( - + + + + {!isFiltered && ( - - this.emojiList = el} - data={this.emojis} - renderItem={this.renderItem} - keyExtractor={item => (`emoji_picker_${item.code}`)} - numColumns={CONST.EMOJI_NUM_PER_ROW} - style={[ - styles.emojiPickerList, - this.isMobileLandscape() && styles.emojiPickerListLandscape, - ]} - stickyHeaderIndices={this.headerRowIndices} - getItemLayout={this.getItemLayout} - showsVerticalScrollIndicator - /> + )} + {this.state.filteredEmojis.length === 0 + ? ( + + + {this.props.translate('common.noResultsFound')} + + + ) + : ( + this.emojiList = el} + keyboardShouldPersistTaps="handled" + data={this.state.filteredEmojis} + renderItem={this.renderItem} + keyExtractor={this.keyExtractor} + numColumns={CONST.EMOJI_NUM_PER_ROW} + style={[ + styles.emojiPickerList, + StyleUtils.getEmojiPickerListHeight(isFiltered), + this.isMobileLandscape() && styles.emojiPickerListLandscape, + ]} + stickyHeaderIndices={this.state.headerIndices} + getItemLayout={this.getItemLayout} + showsVerticalScrollIndicator + + // used because of a bug in RN where stickyHeaderIndices can't be updated after the list is rendered https://github.com/facebook/react-native/issues/25157 + removeClippedSubviews={false} + /> + )} + ); } diff --git a/src/styles/StyleUtils.js b/src/styles/StyleUtils.js index 67e1a9335f90..5ceb0ce76e12 100644 --- a/src/styles/StyleUtils.js +++ b/src/styles/StyleUtils.js @@ -483,7 +483,7 @@ function getFontFamilyMonospace({fontStyle, fontWeight}) { function getEmojiPickerStyle(isSmallScreenWidth) { if (isSmallScreenWidth) { return { - width: '100%', + width: CONST.SMALL_EMOJI_PICKER_SIZE.WIDTH, }; } return { @@ -1014,6 +1014,18 @@ function getGoogleListViewStyle(shouldDisplayBorder) { }; } +/** + * Gets the correct height for emoji picker list based on screen dimensions + * + * @param {Boolean} hasAdditionalSpace + * @returns {Object} + */ +function getEmojiPickerListHeight(hasAdditionalSpace) { + return { + height: hasAdditionalSpace ? CONST.NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT + CONST.CATEGORY_SHORTCUT_BAR_HEIGHT : CONST.NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT, + }; +} + export { getAvatarSize, getAvatarStyle, @@ -1069,4 +1081,5 @@ export { getFontSizeStyle, getSignInWordmarkWidthStyle, getGoogleListViewStyle, + getEmojiPickerListHeight, }; diff --git a/src/styles/styles.js b/src/styles/styles.js index 5f3a0a96b929..b8fde0d5e205 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -1548,7 +1548,12 @@ const styles = { }, emojiPickerList: { - height: 288, + height: CONST.NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT, + width: '100%', + ...spacing.ph4, + }, + emojiPickerListWithPadding: { + height: CONST.NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT + CONST.CATEGORY_SHORTCUT_BAR_HEIGHT, width: '100%', ...spacing.ph4, }, From dc5b6da527e55efdc0b9d283aa5481e0f79b3b45 Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Mon, 1 May 2023 12:50:58 +0200 Subject: [PATCH 03/21] add search input for mobile on WEB --- .../EmojiPicker/EmojiPickerMenu/index.js | 49 ++++++++++++------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.js b/src/components/EmojiPicker/EmojiPickerMenu/index.js index e3ebdbb3cd47..6cba82a907de 100755 --- a/src/components/EmojiPicker/EmojiPickerMenu/index.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/index.js @@ -20,6 +20,7 @@ import EmojiSkinToneList from '../EmojiSkinToneList'; import * as EmojiUtils from '../../../libs/EmojiUtils'; import CategoryShortcutBar from '../CategoryShortcutBar'; import TextInput from '../../TextInput'; +import KeyboardSpacer from '../../KeyboardSpacer'; const propTypes = { /** Function to add the selected emoji to the main compose text input */ @@ -433,6 +434,16 @@ class EmojiPickerMenu extends Component { User.updatePreferredSkinTone(skinTone); } + /** + * Return a unique key for each emoji item + * + * @param {Object} item + * @returns {String} + */ + keyExtractor(item) { + return (`emoji_picker_${item.code}`); + } + /** * Given an emoji item object, render a component based on its type. * Items with the code "SPACER" return nothing and are used to fill rows up to 8 @@ -495,21 +506,20 @@ class EmojiPickerMenu extends Component { style={[styles.emojiPickerContainer, StyleUtils.getEmojiPickerStyle(this.props.isSmallScreenWidth)]} pointerEvents={this.state.arePointerEventsDisabled ? 'none' : 'auto'} > - {!this.props.isSmallScreenWidth && ( - - this.searchInput = el} - autoFocus - selectTextOnFocus={this.state.selectTextOnFocus} - onSelectionChange={this.onSelectionChange} - onFocus={() => this.setState({isFocused: true, highlightedIndex: -1, isUsingKeyboardMovement: false})} - onBlur={() => this.setState({isFocused: false})} - /> - - )} + + this.searchInput = el} + autoFocus={!this.props.isSmallScreenWidth} + selectTextOnFocus={this.state.selectTextOnFocus} + onSelectionChange={this.onSelectionChange} + onFocus={() => this.setState({isFocused: true, highlightedIndex: -1, isUsingKeyboardMovement: false})} + onBlur={() => this.setState({isFocused: false})} + autoCorrect={false} + /> + {!isFiltered && ( this.emojiList = el} data={this.state.filteredEmojis} renderItem={this.renderItem} - keyExtractor={item => `emoji_picker_${item.code}`} + keyExtractor={this.keyExtractor} numColumns={CONST.EMOJI_NUM_PER_ROW} style={[ styles.emojiPickerList, + StyleUtils.getEmojiPickerListHeight(isFiltered), this.isMobileLandscape() && styles.emojiPickerListLandscape, ]} extraData={ @@ -553,6 +567,7 @@ class EmojiPickerMenu extends Component { updatePreferredSkinTone={this.updatePreferredSkinTone} preferredSkinTone={this.props.preferredSkinTone} /> + ); } From 94d8eb7b0df2bf88e882d16e5e1fa947cfc8989d Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Tue, 2 May 2023 15:44:18 +0200 Subject: [PATCH 04/21] remove KeyboardSpacer --- src/components/EmojiPicker/EmojiPicker.js | 4 +++- .../EmojiPicker/EmojiPickerMenu/index.native.js | 2 -- src/components/Modal/BaseModal.js | 15 +++++++++++++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/components/EmojiPicker/EmojiPicker.js b/src/components/EmojiPicker/EmojiPicker.js index c76d52ee6aff..302f4b691de5 100644 --- a/src/components/EmojiPicker/EmojiPicker.js +++ b/src/components/EmojiPicker/EmojiPicker.js @@ -7,6 +7,7 @@ import PopoverWithMeasuredContent from '../PopoverWithMeasuredContent'; import withWindowDimensions, {windowDimensionsPropTypes} from '../withWindowDimensions'; import withViewportOffsetTop, {viewportOffsetTopPropTypes} from '../withViewportOffsetTop'; import compose from '../../libs/compose'; +import * as Browser from '../../libs/Browser'; const DEFAULT_ANCHOR_ORIGIN = { horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT, @@ -185,7 +186,8 @@ class EmojiPicker extends React.Component { }} anchorOrigin={this.state.emojiPopoverAnchorOrigin} measureContent={this.measureContent} - outerStyle={{maxHeight: this.props.windowHeight, marginTop: this.props.viewportOffsetTop}} + outerStyle={Browser.isMobile() && {maxHeight: this.props.windowHeight, marginTop: this.props.viewportOffsetTop}} + useAvoidingView > - ); } diff --git a/src/components/Modal/BaseModal.js b/src/components/Modal/BaseModal.js index 7d44127f1c91..dfe7c86e5755 100644 --- a/src/components/Modal/BaseModal.js +++ b/src/components/Modal/BaseModal.js @@ -1,5 +1,5 @@ import React, {PureComponent} from 'react'; -import {StatusBar, View} from 'react-native'; +import {KeyboardAvoidingView, StatusBar, View} from 'react-native'; import PropTypes from 'prop-types'; import ReactNativeModal from 'react-native-modal'; import {SafeAreaInsetsContext} from 'react-native-safe-area-context'; @@ -158,7 +158,7 @@ class BaseModal extends PureComponent { insets, }); - return ( + const content = ( ); + if (this.props.useAvoidingView) { + return ( + + {content} + + ); + } + return content; }} From c6d1123134fdd261384cc418dd79146348609233 Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Tue, 2 May 2023 16:58:08 +0200 Subject: [PATCH 05/21] clean --- src/components/EmojiPicker/EmojiPickerMenu/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.js b/src/components/EmojiPicker/EmojiPickerMenu/index.js index 6cba82a907de..446a33d543c6 100755 --- a/src/components/EmojiPicker/EmojiPickerMenu/index.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/index.js @@ -20,7 +20,6 @@ import EmojiSkinToneList from '../EmojiSkinToneList'; import * as EmojiUtils from '../../../libs/EmojiUtils'; import CategoryShortcutBar from '../CategoryShortcutBar'; import TextInput from '../../TextInput'; -import KeyboardSpacer from '../../KeyboardSpacer'; const propTypes = { /** Function to add the selected emoji to the main compose text input */ @@ -567,7 +566,6 @@ class EmojiPickerMenu extends Component { updatePreferredSkinTone={this.updatePreferredSkinTone} preferredSkinTone={this.props.preferredSkinTone} /> - ); } From fd06379a8e18e17b1638917f5eeb64c4af7acf34 Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Tue, 2 May 2023 17:07:03 +0200 Subject: [PATCH 06/21] enableKeyboardAvoiding --- src/components/EmojiPicker/EmojiPicker.js | 2 +- src/components/Modal/BaseModal.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/EmojiPicker/EmojiPicker.js b/src/components/EmojiPicker/EmojiPicker.js index 302f4b691de5..af811ce785c0 100644 --- a/src/components/EmojiPicker/EmojiPicker.js +++ b/src/components/EmojiPicker/EmojiPicker.js @@ -187,7 +187,7 @@ class EmojiPicker extends React.Component { anchorOrigin={this.state.emojiPopoverAnchorOrigin} measureContent={this.measureContent} outerStyle={Browser.isMobile() && {maxHeight: this.props.windowHeight, marginTop: this.props.viewportOffsetTop}} - useAvoidingView + enableKeyboardAvoiding > ); - if (this.props.useAvoidingView) { + if (this.props.enableKeyboardAvoiding) { return ( Date: Wed, 10 May 2023 12:17:12 +0200 Subject: [PATCH 07/21] prettier --- src/components/EmojiPicker/EmojiPicker.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/components/EmojiPicker/EmojiPicker.js b/src/components/EmojiPicker/EmojiPicker.js index 66f76545961e..61636806eaff 100644 --- a/src/components/EmojiPicker/EmojiPicker.js +++ b/src/components/EmojiPicker/EmojiPicker.js @@ -202,7 +202,4 @@ class EmojiPicker extends React.Component { EmojiPicker.propTypes = propTypes; -export default compose( - withViewportOffsetTop, - withWindowDimensions, -)(EmojiPicker); +export default compose(withViewportOffsetTop, withWindowDimensions)(EmojiPicker); From 73068e106c3c791bb0a35441af62a7752a5a24fb Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Wed, 10 May 2023 22:18:08 +0200 Subject: [PATCH 08/21] add index to keyExtractor --- src/components/EmojiPicker/EmojiPickerMenu/index.native.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.native.js b/src/components/EmojiPicker/EmojiPickerMenu/index.native.js index 01c44bf58d8f..a83dd828f4de 100644 --- a/src/components/EmojiPicker/EmojiPickerMenu/index.native.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/index.native.js @@ -154,10 +154,11 @@ class EmojiPickerMenu extends Component { * Return a unique key for each emoji item * * @param {Object} item + * @param {Number} index * @returns {String} */ - keyExtractor(item) { - return `emoji_picker_${item.code}`; + keyExtractor(item, index) { + return `${index}${item.code}`; } /** From 6b4d03eca714019a2ea01a97e06620cfec4c1752 Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Thu, 11 May 2023 16:24:15 +0200 Subject: [PATCH 09/21] update getEmojiPickerListHeight style --- src/styles/StyleUtils.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/styles/StyleUtils.js b/src/styles/StyleUtils.js index d4ae5c49b798..cfec4fc896a5 100644 --- a/src/styles/StyleUtils.js +++ b/src/styles/StyleUtils.js @@ -1117,11 +1117,14 @@ function getGoogleListViewStyle(shouldDisplayBorder) { * Gets the correct height for emoji picker list based on screen dimensions * * @param {Boolean} hasAdditionalSpace + * @param {Boolean} isBrowserMobile * @returns {Object} */ -function getEmojiPickerListHeight(hasAdditionalSpace) { +function getEmojiPickerListHeight(hasAdditionalSpace, isBrowserMobile = false) { + const pickerListHeight = isBrowserMobile ? CONST.NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT_WEB : CONST.NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT; return { - height: hasAdditionalSpace ? CONST.NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT + CONST.CATEGORY_SHORTCUT_BAR_HEIGHT : CONST.NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT, + height: hasAdditionalSpace ? pickerListHeight + CONST.CATEGORY_SHORTCUT_BAR_HEIGHT : pickerListHeight, + }; } From f734e1c1dc46990a90019fcd0f307d17f95f5a8f Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Thu, 11 May 2023 16:27:24 +0200 Subject: [PATCH 10/21] reduce the height of the web emoji picker on mobile devices --- src/CONST.js | 3 +- .../EmojiPicker/EmojiPickerMenu/index.js | 126 ++++++++---------- .../EmojiPickerMenu/index.native.js | 3 +- src/styles/styles.js | 3 - 4 files changed, 62 insertions(+), 73 deletions(-) diff --git a/src/CONST.js b/src/CONST.js index f307427f466a..0e1d81015dee 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -729,7 +729,8 @@ const CONST = { SMALL_EMOJI_PICKER_SIZE: { WIDTH: '100%', }, - NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT: 256, + NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT: 238, + NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT_WEB: 210, EMOJI_PICKER_ITEM_HEIGHT: 32, EMOJI_PICKER_HEADER_HEIGHT: 32, RECIPIENT_LOCAL_TIME_HEIGHT: 25, diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.js b/src/components/EmojiPicker/EmojiPickerMenu/index.js index 7690e98be99b..d03c42175942 100755 --- a/src/components/EmojiPicker/EmojiPickerMenu/index.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/index.js @@ -21,6 +21,7 @@ import * as EmojiUtils from '../../../libs/EmojiUtils'; import CategoryShortcutBar from '../CategoryShortcutBar'; import TextInput from '../../TextInput'; import isEnterWhileComposition from '../../../libs/KeyboardShortcut/isEnterWhileComposition'; +import * as Browser from '../../../libs/Browser'; const propTypes = { /** Function to add the selected emoji to the main compose text input */ @@ -33,10 +34,12 @@ const propTypes = { preferredSkinTone: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), /** User's frequently used emojis */ - frequentlyUsedEmojis: PropTypes.arrayOf(PropTypes.shape({ - code: PropTypes.string.isRequired, - keywords: PropTypes.arrayOf(PropTypes.string), - })), + frequentlyUsedEmojis: PropTypes.arrayOf( + PropTypes.shape({ + code: PropTypes.string.isRequired, + keywords: PropTypes.arrayOf(PropTypes.string), + }), + ), /** Props related to the dimensions of the window */ ...windowDimensionsPropTypes, @@ -172,8 +175,7 @@ class EmojiPickerMenu extends Component { // Enable keyboard movement if tab or enter is pressed or if shift is pressed while the input // is not focused, so that the navigation and tab cycling can be done using the keyboard without // interfering with the input behaviour. - if (keyBoardEvent.key === 'Tab' || keyBoardEvent.key === 'Enter' - || (keyBoardEvent.key === 'Shift' && this.searchInput && !this.searchInput.isFocused())) { + if (keyBoardEvent.key === 'Tab' || keyBoardEvent.key === 'Enter' || (keyBoardEvent.key === 'Shift' && this.searchInput && !this.searchInput.isFocused())) { this.setState({isUsingKeyboardMovement: true}); return; } @@ -265,12 +267,7 @@ class EmojiPickerMenu extends Component { return; } - if (arrowKey === 'ArrowRight' - && !( - this.searchInput.value.length === this.state.selection.start - && this.state.selection.start === this.state.selection.end - ) - ) { + if (arrowKey === 'ArrowRight' && !(this.searchInput.value.length === this.state.selection.start && this.state.selection.start === this.state.selection.end)) { return; } @@ -312,19 +309,18 @@ class EmojiPickerMenu extends Component { switch (arrowKey) { case 'ArrowDown': - move( - CONST.EMOJI_NUM_PER_ROW, - () => this.state.highlightedIndex + CONST.EMOJI_NUM_PER_ROW > this.state.filteredEmojis.length - 1, - ); + move(CONST.EMOJI_NUM_PER_ROW, () => this.state.highlightedIndex + CONST.EMOJI_NUM_PER_ROW > this.state.filteredEmojis.length - 1); break; case 'ArrowLeft': - move(-1, + move( + -1, () => this.state.highlightedIndex - 1 < this.firstNonHeaderIndex, () => { // Reaching start of the list, arrow left set the focus to searchInput. this.focusInputWithTextSelect(); newIndex = -1; - }); + }, + ); break; case 'ArrowRight': move(1, () => this.state.highlightedIndex + 1 > this.state.filteredEmojis.length - 1); @@ -441,7 +437,7 @@ class EmojiPickerMenu extends Component { * @returns {String} */ keyExtractor(item) { - return (`emoji_picker_${item.code}`); + return `emoji_picker_${item.code}`; } /** @@ -462,16 +458,12 @@ class EmojiPickerMenu extends Component { if (header) { return ( - - {this.props.translate(`emojiPicker.headers.${code}`)} - + {this.props.translate(`emojiPicker.headers.${code}`)} ); } - const emojiCode = types && types[this.props.preferredSkinTone] - ? types[this.props.preferredSkinTone] - : code; + const emojiCode = types && types[this.props.preferredSkinTone] ? types[this.props.preferredSkinTone] : code; const isEmojiFocused = index === this.state.highlightedIndex && this.state.isUsingKeyboardMovement; @@ -511,7 +503,7 @@ class EmojiPickerMenu extends Component { label={this.props.translate('common.search')} onChangeText={this.filterEmojis} defaultValue="" - ref={el => this.searchInput = el} + ref={el => (this.searchInput = el)} autoFocus={!this.props.isSmallScreenWidth} selectTextOnFocus={this.state.selectTextOnFocus} onSelectionChange={this.onSelectionChange} @@ -526,43 +518,38 @@ class EmojiPickerMenu extends Component { onPress={this.scrollToHeader} /> )} - {this.state.filteredEmojis.length === 0 - ? ( - - {this.props.translate('common.noResultsFound')} - - ) - : ( - this.emojiList = el} - data={this.state.filteredEmojis} - renderItem={this.renderItem} - keyExtractor={this.keyExtractor} - numColumns={CONST.EMOJI_NUM_PER_ROW} - style={[ - styles.emojiPickerList, - StyleUtils.getEmojiPickerListHeight(isFiltered), - this.isMobileLandscape() && styles.emojiPickerListLandscape, - ]} - extraData={ - [this.state.filteredEmojis, this.state.highlightedIndex, this.props.preferredSkinTone] - } - stickyHeaderIndices={this.state.headerIndices} - onScroll={e => this.currentScrollOffset = e.nativeEvent.contentOffset.y} - getItemLayout={this.getItemLayout} - /> - )} + {this.state.filteredEmojis.length === 0 ? ( + + {this.props.translate('common.noResultsFound')} + + ) : ( + (this.emojiList = el)} + data={this.state.filteredEmojis} + renderItem={this.renderItem} + keyExtractor={this.keyExtractor} + numColumns={CONST.EMOJI_NUM_PER_ROW} + style={[ + styles.emojiPickerList, + StyleUtils.getEmojiPickerListHeight(isFiltered, Browser.isMobile()), + ]} + extraData={[this.state.filteredEmojis, this.state.highlightedIndex, this.props.preferredSkinTone]} + stickyHeaderIndices={this.state.headerIndices} + onScroll={e => (this.currentScrollOffset = e.nativeEvent.contentOffset.y)} + getItemLayout={this.getItemLayout} + /> + )} ( - // eslint-disable-next-line react/jsx-props-no-spreading - -))); +)( + React.forwardRef((props, ref) => ( + + )), +); diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.native.js b/src/components/EmojiPicker/EmojiPickerMenu/index.native.js index 636b80cdd941..e74e12196c91 100644 --- a/src/components/EmojiPicker/EmojiPickerMenu/index.native.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/index.native.js @@ -216,7 +216,7 @@ class EmojiPickerMenu extends Component { styles.alignItemsCenter, styles.justifyContentCenter, styles.emojiPickerListWithPadding, - this.isMobileLandscape() && styles.emojiPickerListLandscape, + StyleUtils.getEmojiPickerListHeight(isFiltered), ]} > @@ -235,7 +235,6 @@ class EmojiPickerMenu extends Component { style={[ styles.emojiPickerList, StyleUtils.getEmojiPickerListHeight(isFiltered), - this.isMobileLandscape() && styles.emojiPickerListLandscape, ]} stickyHeaderIndices={this.state.headerIndices} getItemLayout={this.getItemLayout} diff --git a/src/styles/styles.js b/src/styles/styles.js index d4c6ec1f6b8c..420d81792a34 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -1588,9 +1588,6 @@ const styles = { width: '100%', ...spacing.ph4, }, - emojiPickerListLandscape: { - height: 240, - }, emojiHeaderContainer: { backgroundColor: themeColors.componentBG, From 1b0ae8348097bd7d069d444a6a583f40b401e45f Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Thu, 1 Jun 2023 11:50:10 +0200 Subject: [PATCH 11/21] make content resizable --- src/CONST.js | 4 +-- src/components/EmojiPicker/EmojiPicker.js | 6 ++-- .../EmojiPicker/EmojiPickerMenu/index.js | 28 ++++++------------- .../EmojiPickerMenu/index.native.js | 19 ++++++++----- .../EmojiPicker/EmojiSkinToneList.js | 2 +- src/components/Modal/BaseModal.js | 18 +++--------- src/components/Modal/index.web.js | 1 + src/styles/StyleUtils.js | 16 ++++++++--- 8 files changed, 44 insertions(+), 50 deletions(-) diff --git a/src/CONST.js b/src/CONST.js index 469a6f2555ea..34abe9aaeaff 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -795,8 +795,8 @@ const CONST = { SMALL_EMOJI_PICKER_SIZE: { WIDTH: '100%', }, - NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT: 238, - NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT_WEB: 210, + NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT: 300, + NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT_WEB: 200, EMOJI_PICKER_ITEM_HEIGHT: 32, EMOJI_PICKER_HEADER_HEIGHT: 32, RECIPIENT_LOCAL_TIME_HEIGHT: 25, diff --git a/src/components/EmojiPicker/EmojiPicker.js b/src/components/EmojiPicker/EmojiPicker.js index 849242a56fc8..aaca4f961cee 100644 --- a/src/components/EmojiPicker/EmojiPicker.js +++ b/src/components/EmojiPicker/EmojiPicker.js @@ -1,5 +1,5 @@ import React from 'react'; -import {Dimensions, Keyboard} from 'react-native'; +import {Dimensions, Keyboard, Platform} from 'react-native'; import _ from 'underscore'; import EmojiPickerMenu from './EmojiPickerMenu'; import CONST from '../../CONST'; @@ -8,6 +8,7 @@ import withWindowDimensions, {windowDimensionsPropTypes} from '../withWindowDime import withViewportOffsetTop, {viewportOffsetTopPropTypes} from '../withViewportOffsetTop'; import compose from '../../libs/compose'; import * as Browser from '../../libs/Browser'; +import styles from '../../styles/styles'; const DEFAULT_ANCHOR_ORIGIN = { horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT, @@ -169,7 +170,8 @@ class EmojiPicker extends React.Component { }} outerStyle={Browser.isMobile() && {maxHeight: this.props.windowHeight, marginTop: this.props.viewportOffsetTop}} anchorAlignment={this.state.emojiPopoverAnchorOrigin} - enableKeyboardAvoiding + innerContainerStyle={{paddingTop: 4, maxHeight: '95%'}} + avoidKeyboard > - + )} - {this.state.filteredEmojis.length === 0 ? ( - - {this.props.translate('common.noResultsFound')} - - ) : ( (this.emojiList = el)} data={this.state.filteredEmojis} renderItem={this.renderItem} keyExtractor={this.keyExtractor} numColumns={CONST.EMOJI_NUM_PER_ROW} - style={[styles.emojiPickerList, StyleUtils.getEmojiPickerListHeight(isFiltered, Browser.isMobile())]} + style={StyleUtils.getEmojiPickerListHeight(isFiltered, this.props.windowHeight)} extraData={[this.state.filteredEmojis, this.state.highlightedIndex, this.props.preferredSkinTone]} stickyHeaderIndices={this.state.headerIndices} onScroll={(e) => (this.currentScrollOffset = e.nativeEvent.contentOffset.y)} getItemLayout={this.getItemLayout} + contentContainerStyle={styles.flexGrow1} + ListEmptyComponent={ + + {this.props.translate('common.noResultsFound')} + + } /> - )} )} - {this.state.filteredEmojis.length === 0 ? ( - - {this.props.translate('common.noResultsFound')} - - ) : ( (this.emojiList = el)} keyboardShouldPersistTaps="handled" @@ -213,14 +208,24 @@ class EmojiPickerMenu extends Component { renderItem={this.renderItem} keyExtractor={this.keyExtractor} numColumns={CONST.EMOJI_NUM_PER_ROW} - style={[styles.emojiPickerList, StyleUtils.getEmojiPickerListHeight(isFiltered)]} + style={[ + StyleUtils.getEmojiPickerListHeight(isFiltered), + { + width: this.props.windowWidth, + }, + ]} stickyHeaderIndices={this.state.headerIndices} getItemLayout={this.getItemLayout} showsVerticalScrollIndicator // used because of a bug in RN where stickyHeaderIndices can't be updated after the list is rendered https://github.com/facebook/react-native/issues/25157 removeClippedSubviews={false} + contentContainerStyle={styles.flexGrow1} + ListEmptyComponent={ + + {this.props.translate('common.noResultsFound')} + + } /> - )} + {!this.state.isSkinToneListVisible && ( this.setState((prev) => ({isSkinToneListVisible: !prev.isSkinToneListVisible}))} diff --git a/src/components/Modal/BaseModal.js b/src/components/Modal/BaseModal.js index e8417e56dba8..8ff2a90900c1 100644 --- a/src/components/Modal/BaseModal.js +++ b/src/components/Modal/BaseModal.js @@ -1,5 +1,5 @@ import React, {PureComponent} from 'react'; -import {KeyboardAvoidingView, StatusBar, View} from 'react-native'; +import { StatusBar, View} from 'react-native'; import PropTypes from 'prop-types'; import ReactNativeModal from 'react-native-modal'; import {SafeAreaInsetsContext} from 'react-native-safe-area-context'; @@ -139,6 +139,7 @@ class BaseModal extends PureComponent { animationOutTiming={this.props.animationOutTiming} statusBarTranslucent={this.props.statusBarTranslucent} onLayout={this.props.onLayout} + avoidKeyboard={this.props.avoidKeyboard} > {(insets) => { @@ -165,8 +166,8 @@ class BaseModal extends PureComponent { insets, }); - const content = ( - {this.props.children} - ); - if (this.props.enableKeyboardAvoiding) { - return ( - - {content} - ); - } - return content; }} diff --git a/src/components/Modal/index.web.js b/src/components/Modal/index.web.js index b79080b9789d..a4c396e5efdb 100644 --- a/src/components/Modal/index.web.js +++ b/src/components/Modal/index.web.js @@ -34,6 +34,7 @@ const Modal = (props) => { {...props} onModalHide={hideModal} onModalShow={showModal} + avoidKeyboard={false} > {props.children} diff --git a/src/styles/StyleUtils.js b/src/styles/StyleUtils.js index f5b4bdafad81..7c97e74f0576 100644 --- a/src/styles/StyleUtils.js +++ b/src/styles/StyleUtils.js @@ -1103,14 +1103,22 @@ function getGoogleListViewStyle(shouldDisplayBorder) { * Gets the correct height for emoji picker list based on screen dimensions * * @param {Boolean} hasAdditionalSpace - * @param {Boolean} isBrowserMobile + * @param {Number} windowHeight * @returns {Object} */ -function getEmojiPickerListHeight(hasAdditionalSpace, isBrowserMobile = false) { - const pickerListHeight = isBrowserMobile ? CONST.NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT_WEB : CONST.NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT; +function getEmojiPickerListHeight(hasAdditionalSpace, windowHeight) { + if(windowHeight){ + const dim = hasAdditionalSpace ? 120 : 120 + CONST.CATEGORY_SHORTCUT_BAR_HEIGHT return { - height: hasAdditionalSpace ? pickerListHeight + CONST.CATEGORY_SHORTCUT_BAR_HEIGHT : pickerListHeight, + paddingHorizontal: 16, + height: hasAdditionalSpace ? CONST.NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT + CONST.CATEGORY_SHORTCUT_BAR_HEIGHT : CONST.NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT, + maxHeight: windowHeight - dim }; + } + return { + paddingHorizontal: 16, + height: hasAdditionalSpace ? CONST.NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT + CONST.CATEGORY_SHORTCUT_BAR_HEIGHT : CONST.NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT, + }; } /** From a25f77c770a4bf0c17a00a78247d39436803ddbd Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Thu, 1 Jun 2023 11:54:34 +0200 Subject: [PATCH 12/21] patch-package react-native-modal --- patches/react-native-modal+13.0.1.patch | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/patches/react-native-modal+13.0.1.patch b/patches/react-native-modal+13.0.1.patch index 576858f1f5f7..049a7a09d16a 100644 --- a/patches/react-native-modal+13.0.1.patch +++ b/patches/react-native-modal+13.0.1.patch @@ -11,7 +11,7 @@ index b63bcfc..bd6419e 100644 buildPanResponder: () => void; getAccDistancePerDirection: (gestureState: PanResponderGestureState) => number; diff --git a/node_modules/react-native-modal/dist/modal.js b/node_modules/react-native-modal/dist/modal.js -index 80f4e75..fe028ab 100644 +index 80f4e75..a88a2ca 100644 --- a/node_modules/react-native-modal/dist/modal.js +++ b/node_modules/react-native-modal/dist/modal.js @@ -75,6 +75,13 @@ export class ReactNativeModal extends React.Component { @@ -44,3 +44,12 @@ index 80f4e75..fe028ab 100644 if (this.didUpdateDimensionsEmitter) { this.didUpdateDimensionsEmitter.remove(); } +@@ -525,7 +538,7 @@ export class ReactNativeModal extends React.Component { + } + return (React.createElement(Modal, Object.assign({ transparent: true, animationType: 'none', visible: this.state.isVisible, onRequestClose: onBackButtonPress }, otherProps), + this.makeBackdrop(), +- avoidKeyboard ? (React.createElement(KeyboardAvoidingView, { behavior: Platform.OS === 'ios' ? 'padding' : undefined, pointerEvents: "box-none", style: computedStyle.concat([{ margin: 0 }]) }, containerView)) : (containerView))); ++ avoidKeyboard ? (React.createElement(KeyboardAvoidingView, { behavior: 'padding', pointerEvents: "box-none", style: computedStyle.concat([{ margin: 0 }]) }, containerView)) : (containerView))); + } + } + ReactNativeModal.propTypes = { From 38d229504d313b06d188d871b7b14d97808ce4f9 Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Thu, 1 Jun 2023 15:23:33 +0200 Subject: [PATCH 13/21] lint --- src/components/EmojiPicker/EmojiPicker.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/EmojiPicker/EmojiPicker.js b/src/components/EmojiPicker/EmojiPicker.js index b986a633ade4..35dbb104e8be 100644 --- a/src/components/EmojiPicker/EmojiPicker.js +++ b/src/components/EmojiPicker/EmojiPicker.js @@ -1,5 +1,5 @@ import React from 'react'; -import {Dimensions, Keyboard, Platform} from 'react-native'; +import {Dimensions, Keyboard} from 'react-native'; import _ from 'underscore'; import EmojiPickerMenu from './EmojiPickerMenu'; import CONST from '../../CONST'; @@ -8,7 +8,6 @@ import withWindowDimensions, {windowDimensionsPropTypes} from '../withWindowDime import withViewportOffsetTop, {viewportOffsetTopPropTypes} from '../withViewportOffsetTop'; import compose from '../../libs/compose'; import * as Browser from '../../libs/Browser'; -import styles from '../../styles/styles'; const DEFAULT_ANCHOR_ORIGIN = { horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT, From f69bb5b40528d8b4b687f80c1a8388510ddbfa1f Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Thu, 1 Jun 2023 15:57:51 +0200 Subject: [PATCH 14/21] linter --- src/CONST.js | 1 + src/components/Modal/BaseModal.js | 26 +++++++++++++------------- src/styles/StyleUtils.js | 15 ++++++++------- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/CONST.js b/src/CONST.js index 61ad2b05fa25..cfdf33218cd3 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -2448,6 +2448,7 @@ const CONST = { FLAG_SEVERITY_HARASSMENT: 'harassment', FLAG_SEVERITY_ASSAULT: 'assault', }, + EMOJI_PICKER_TEXT_INPUT_SIZES: 130 }; export default CONST; diff --git a/src/components/Modal/BaseModal.js b/src/components/Modal/BaseModal.js index 8e6fd308b0d9..c89bec0e1753 100644 --- a/src/components/Modal/BaseModal.js +++ b/src/components/Modal/BaseModal.js @@ -164,19 +164,19 @@ class BaseModal extends PureComponent { insets, }); - return ( - - {this.props.children} - - ); + return ( + + {this.props.children} + + ); }} diff --git a/src/styles/StyleUtils.js b/src/styles/StyleUtils.js index 25fb031752fa..861fd085f0e8 100644 --- a/src/styles/StyleUtils.js +++ b/src/styles/StyleUtils.js @@ -1134,18 +1134,19 @@ function getGoogleListViewStyle(shouldDisplayBorder) { * @returns {Object} */ function getEmojiPickerListHeight(hasAdditionalSpace, windowHeight) { + const style = { + paddingHorizontal: 16, + height: hasAdditionalSpace ? CONST.NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT + CONST.CATEGORY_SHORTCUT_BAR_HEIGHT : CONST.NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT, + } + if(windowHeight){ - const dim = hasAdditionalSpace ? 120 : 120 + CONST.CATEGORY_SHORTCUT_BAR_HEIGHT + const dim = hasAdditionalSpace ? CONST.EMOJI_PICKER_TEXT_INPUT_SIZES : CONST.EMOJI_PICKER_TEXT_INPUT_SIZES + CONST.CATEGORY_SHORTCUT_BAR_HEIGHT return { - paddingHorizontal: 16, - height: hasAdditionalSpace ? CONST.NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT + CONST.CATEGORY_SHORTCUT_BAR_HEIGHT : CONST.NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT, + ...style, maxHeight: windowHeight - dim }; } - return { - paddingHorizontal: 16, - height: hasAdditionalSpace ? CONST.NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT + CONST.CATEGORY_SHORTCUT_BAR_HEIGHT : CONST.NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT, - }; + return style; } /** From e7c137f42b88382099d6f0e7b5a2daa64c3ed644 Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Thu, 1 Jun 2023 16:36:02 +0200 Subject: [PATCH 15/21] clean code --- src/CONST.js | 2 +- .../EmojiPicker/EmojiPickerMenu/index.js | 36 ++++++++-------- .../EmojiPickerMenu/index.native.js | 42 +++++++++---------- .../EmojiPicker/EmojiSkinToneList.js | 1 - src/components/Modal/BaseModal.js | 22 +++++----- src/styles/StyleUtils.js | 24 +++++------ 6 files changed, 63 insertions(+), 64 deletions(-) diff --git a/src/CONST.js b/src/CONST.js index cfdf33218cd3..09c04c22cb48 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -2448,7 +2448,7 @@ const CONST = { FLAG_SEVERITY_HARASSMENT: 'harassment', FLAG_SEVERITY_ASSAULT: 'assault', }, - EMOJI_PICKER_TEXT_INPUT_SIZES: 130 + EMOJI_PICKER_TEXT_INPUT_SIZES: 130, }; export default CONST; diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.js b/src/components/EmojiPicker/EmojiPickerMenu/index.js index 5b532cdc38df..d2aae0965dd5 100755 --- a/src/components/EmojiPicker/EmojiPickerMenu/index.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/index.js @@ -512,24 +512,24 @@ class EmojiPickerMenu extends Component { onPress={this.scrollToHeader} /> )} - (this.emojiList = el)} - data={this.state.filteredEmojis} - renderItem={this.renderItem} - keyExtractor={this.keyExtractor} - numColumns={CONST.EMOJI_NUM_PER_ROW} - style={StyleUtils.getEmojiPickerListHeight(isFiltered, this.props.windowHeight)} - extraData={[this.state.filteredEmojis, this.state.highlightedIndex, this.props.preferredSkinTone]} - stickyHeaderIndices={this.state.headerIndices} - onScroll={(e) => (this.currentScrollOffset = e.nativeEvent.contentOffset.y)} - getItemLayout={this.getItemLayout} - contentContainerStyle={styles.flexGrow1} - ListEmptyComponent={ - - {this.props.translate('common.noResultsFound')} - - } - /> + (this.emojiList = el)} + data={this.state.filteredEmojis} + renderItem={this.renderItem} + keyExtractor={this.keyExtractor} + numColumns={CONST.EMOJI_NUM_PER_ROW} + style={StyleUtils.getEmojiPickerListHeight(isFiltered, this.props.windowHeight)} + extraData={[this.state.filteredEmojis, this.state.highlightedIndex, this.props.preferredSkinTone]} + stickyHeaderIndices={this.state.headerIndices} + onScroll={(e) => (this.currentScrollOffset = e.nativeEvent.contentOffset.y)} + getItemLayout={this.getItemLayout} + contentContainerStyle={styles.flexGrow1} + ListEmptyComponent={ + + {this.props.translate('common.noResultsFound')} + + } + /> )} - (this.emojiList = el)} - keyboardShouldPersistTaps="handled" - data={this.state.filteredEmojis} - renderItem={this.renderItem} - keyExtractor={this.keyExtractor} - numColumns={CONST.EMOJI_NUM_PER_ROW} - style={[ + (this.emojiList = el)} + keyboardShouldPersistTaps="handled" + data={this.state.filteredEmojis} + renderItem={this.renderItem} + keyExtractor={this.keyExtractor} + numColumns={CONST.EMOJI_NUM_PER_ROW} + style={[ StyleUtils.getEmojiPickerListHeight(isFiltered), { - width: this.props.windowWidth, + width: this.props.windowWidth, }, - ]} - stickyHeaderIndices={this.state.headerIndices} - getItemLayout={this.getItemLayout} - showsVerticalScrollIndicator - // used because of a bug in RN where stickyHeaderIndices can't be updated after the list is rendered https://github.com/facebook/react-native/issues/25157 - removeClippedSubviews={false} - contentContainerStyle={styles.flexGrow1} - ListEmptyComponent={ - + ]} + stickyHeaderIndices={this.state.headerIndices} + getItemLayout={this.getItemLayout} + showsVerticalScrollIndicator + // used because of a bug in RN where stickyHeaderIndices can't be updated after the list is rendered https://github.com/facebook/react-native/issues/25157 + removeClippedSubviews={false} + contentContainerStyle={styles.flexGrow1} + ListEmptyComponent={ + {this.props.translate('common.noResultsFound')} - - } - /> + + } + /> {currentSkinTone.code} - {props.translate('emojiPicker.skinTonePickerLabel')} diff --git a/src/components/Modal/BaseModal.js b/src/components/Modal/BaseModal.js index c89bec0e1753..d1c10f5e92ca 100644 --- a/src/components/Modal/BaseModal.js +++ b/src/components/Modal/BaseModal.js @@ -165,17 +165,17 @@ class BaseModal extends PureComponent { }); return ( - - {this.props.children} - + + {this.props.children} + ); }} diff --git a/src/styles/StyleUtils.js b/src/styles/StyleUtils.js index 861fd085f0e8..86cf16905900 100644 --- a/src/styles/StyleUtils.js +++ b/src/styles/StyleUtils.js @@ -1134,19 +1134,19 @@ function getGoogleListViewStyle(shouldDisplayBorder) { * @returns {Object} */ function getEmojiPickerListHeight(hasAdditionalSpace, windowHeight) { - const style = { - paddingHorizontal: 16, - height: hasAdditionalSpace ? CONST.NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT + CONST.CATEGORY_SHORTCUT_BAR_HEIGHT : CONST.NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT, - } - - if(windowHeight){ - const dim = hasAdditionalSpace ? CONST.EMOJI_PICKER_TEXT_INPUT_SIZES : CONST.EMOJI_PICKER_TEXT_INPUT_SIZES + CONST.CATEGORY_SHORTCUT_BAR_HEIGHT - return { - ...style, - maxHeight: windowHeight - dim + const style = { + paddingHorizontal: 16, + height: hasAdditionalSpace ? CONST.NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT + CONST.CATEGORY_SHORTCUT_BAR_HEIGHT : CONST.NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT, }; - } - return style; + + if (windowHeight) { + const dim = hasAdditionalSpace ? CONST.EMOJI_PICKER_TEXT_INPUT_SIZES : CONST.EMOJI_PICKER_TEXT_INPUT_SIZES + CONST.CATEGORY_SHORTCUT_BAR_HEIGHT; + return { + ...style, + maxHeight: windowHeight - dim, + }; + } + return style; } /** From 1d0ef4230f525e707a4d3cb6211656f6a16a5d2e Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Mon, 5 Jun 2023 15:49:27 +0200 Subject: [PATCH 16/21] Add top padding consistent with the WEB version for uniformity across platforms --- src/CONST.js | 2 +- src/components/EmojiPicker/EmojiPicker.js | 3 ++- .../EmojiPicker/EmojiPickerMenu/index.native.js | 2 +- src/styles/StyleUtils.js | 3 ++- src/styles/styles.js | 16 +++++----------- 5 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/CONST.js b/src/CONST.js index 5348abdbcf32..c123406229c9 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -2448,7 +2448,7 @@ const CONST = { FLAG_SEVERITY_HARASSMENT: 'harassment', FLAG_SEVERITY_ASSAULT: 'assault', }, - EMOJI_PICKER_TEXT_INPUT_SIZES: 140, + EMOJI_PICKER_TEXT_INPUT_SIZES: 152, }; export default CONST; diff --git a/src/components/EmojiPicker/EmojiPicker.js b/src/components/EmojiPicker/EmojiPicker.js index 35dbb104e8be..3a743b1c43ff 100644 --- a/src/components/EmojiPicker/EmojiPicker.js +++ b/src/components/EmojiPicker/EmojiPicker.js @@ -3,6 +3,7 @@ import {Dimensions, Keyboard} from 'react-native'; import _ from 'underscore'; import EmojiPickerMenu from './EmojiPickerMenu'; import CONST from '../../CONST'; +import styles from '../../styles/styles'; import PopoverWithMeasuredContent from '../PopoverWithMeasuredContent'; import withWindowDimensions, {windowDimensionsPropTypes} from '../withWindowDimensions'; import withViewportOffsetTop, {viewportOffsetTopPropTypes} from '../withViewportOffsetTop'; @@ -173,7 +174,7 @@ class EmojiPicker extends React.Component { }} outerStyle={Browser.isMobile() && {maxHeight: this.props.windowHeight, marginTop: this.props.viewportOffsetTop}} anchorAlignment={this.state.emojiPopoverAnchorOrigin} - innerContainerStyle={{paddingTop: 4, maxHeight: '95%'}} + innerContainerStyle={styles.popoverInnerContainer} avoidKeyboard > - + Date: Mon, 5 Jun 2023 16:02:56 +0200 Subject: [PATCH 17/21] clean styles --- src/styles/styles.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/styles/styles.js b/src/styles/styles.js index 92a250c70f36..0b56b444a5ec 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -1285,8 +1285,8 @@ const styles = { }, popoverInnerContainer: { - paddingTop: 0, // adjusting this because the mobile modal adds additional padding that we don't need for our layout - maxHeight: '95%' + paddingTop: 0, // adjusting this because the mobile modal adds additional padding that we don't need for our layout + maxHeight: '95%', }, menuItemTextContainer: { From eb687d3d7de52a97bc518af9612d4127e725fdcc Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Mon, 5 Jun 2023 18:01:42 +0200 Subject: [PATCH 18/21] prop-types and the default value for avoidKeyboard --- src/components/Modal/modalPropTypes.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/Modal/modalPropTypes.js b/src/components/Modal/modalPropTypes.js index e33b4a2e8785..820340f9d93e 100644 --- a/src/components/Modal/modalPropTypes.js +++ b/src/components/Modal/modalPropTypes.js @@ -55,6 +55,9 @@ const propTypes = { /** Whether the modal should go under the system statusbar */ statusBarTranslucent: PropTypes.bool, + /** Whether the modal should avoid the keyboard */ + avoidKeyboard: PropTypes.bool, + ...windowDimensionsPropTypes, }; @@ -71,6 +74,7 @@ const defaultProps = { popoverAnchorPosition: {}, innerContainerStyle: {}, statusBarTranslucent: true, + avoidKeyboard: false, }; export {propTypes, defaultProps}; From 251ecbe44d1f3141f20a23a86a76ec84d816bffb Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Mon, 5 Jun 2023 18:14:19 +0200 Subject: [PATCH 19/21] getOuterModalStyle --- src/components/EmojiPicker/EmojiPicker.js | 4 ++-- src/styles/StyleUtils.js | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/components/EmojiPicker/EmojiPicker.js b/src/components/EmojiPicker/EmojiPicker.js index 3a743b1c43ff..ed1a349f4ea2 100644 --- a/src/components/EmojiPicker/EmojiPicker.js +++ b/src/components/EmojiPicker/EmojiPicker.js @@ -8,7 +8,7 @@ import PopoverWithMeasuredContent from '../PopoverWithMeasuredContent'; import withWindowDimensions, {windowDimensionsPropTypes} from '../withWindowDimensions'; import withViewportOffsetTop, {viewportOffsetTopPropTypes} from '../withViewportOffsetTop'; import compose from '../../libs/compose'; -import * as Browser from '../../libs/Browser'; +import * as StyleUtils from '../../styles/StyleUtils'; const DEFAULT_ANCHOR_ORIGIN = { horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT, @@ -172,7 +172,7 @@ class EmojiPicker extends React.Component { width: CONST.EMOJI_PICKER_SIZE.WIDTH, height: CONST.EMOJI_PICKER_SIZE.HEIGHT, }} - outerStyle={Browser.isMobile() && {maxHeight: this.props.windowHeight, marginTop: this.props.viewportOffsetTop}} + outerStyle={StyleUtils.getOuterModalStyle(this.props.windowHeight, this.props.viewportOffsetTop)} anchorAlignment={this.state.emojiPopoverAnchorOrigin} innerContainerStyle={styles.popoverInnerContainer} avoidKeyboard diff --git a/src/styles/StyleUtils.js b/src/styles/StyleUtils.js index 832ea0d8e19a..ba25c744ae3b 100644 --- a/src/styles/StyleUtils.js +++ b/src/styles/StyleUtils.js @@ -8,6 +8,7 @@ import positioning from './utilities/positioning'; import styles from './styles'; import spacing from './utilities/spacing'; import * as UserUtils from '../libs/UserUtils'; +import * as Browser from '../libs/Browser'; const workspaceColorOptions = [ {backgroundColor: colors.blue200, fill: colors.blue700}, @@ -1185,6 +1186,16 @@ function getMentionTextColor(isOurMention) { return isOurMention ? themeColors.ourMentionText : themeColors.mentionText; } +/** + * Returns style object for the mobile on WEB + * @param {Number} windowHeight + * @param {Number} viewportOffsetTop + * @returns {Object} + */ +function getOuterModalStyle(windowHeight, viewportOffsetTop) { + return Browser.isMobile() && {maxHeight: windowHeight, marginTop: viewportOffsetTop}; +} + export { getAvatarSize, getAvatarStyle, @@ -1251,4 +1262,5 @@ export { getMentionStyle, getMentionTextColor, getHeightOfMagicCodeInput, + getOuterModalStyle, }; From e9fc1d141704a09561a037417b737fac1d5423b2 Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Mon, 5 Jun 2023 20:03:01 +0200 Subject: [PATCH 20/21] update getOuterModalStyle --- src/styles/StyleUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles/StyleUtils.js b/src/styles/StyleUtils.js index ba25c744ae3b..3d9182d19eff 100644 --- a/src/styles/StyleUtils.js +++ b/src/styles/StyleUtils.js @@ -1193,7 +1193,7 @@ function getMentionTextColor(isOurMention) { * @returns {Object} */ function getOuterModalStyle(windowHeight, viewportOffsetTop) { - return Browser.isMobile() && {maxHeight: windowHeight, marginTop: viewportOffsetTop}; + return Browser.isMobile() ? {maxHeight: windowHeight, marginTop: viewportOffsetTop} : {}; } export { From 6beba0b8ce3b4689db48dde7a9a5991f58a00098 Mon Sep 17 00:00:00 2001 From: Taras Perun Date: Wed, 7 Jun 2023 16:35:10 +0200 Subject: [PATCH 21/21] add comment --- src/styles/StyleUtils.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/styles/StyleUtils.js b/src/styles/StyleUtils.js index 3d9182d19eff..3be9f626ed92 100644 --- a/src/styles/StyleUtils.js +++ b/src/styles/StyleUtils.js @@ -1154,10 +1154,11 @@ function getEmojiPickerListHeight(hasAdditionalSpace, windowHeight) { }; if (windowHeight) { - const dim = hasAdditionalSpace ? CONST.EMOJI_PICKER_TEXT_INPUT_SIZES : CONST.EMOJI_PICKER_TEXT_INPUT_SIZES + CONST.CATEGORY_SHORTCUT_BAR_HEIGHT; + // dimensions of content above the emoji picker list + const dimensions = hasAdditionalSpace ? CONST.EMOJI_PICKER_TEXT_INPUT_SIZES : CONST.EMOJI_PICKER_TEXT_INPUT_SIZES + CONST.CATEGORY_SHORTCUT_BAR_HEIGHT; return { ...style, - maxHeight: windowHeight - dim, + maxHeight: windowHeight - dimensions, }; } return style;