-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Migrate EmojiPickerMenu to FlashList #31479
Merged
roryabraham
merged 31 commits into
Expensify:main
from
TMisiukiewicz:feat/emojipicker-flashlist-migration
Dec 22, 2023
Merged
Changes from all commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
943a2d3
initial migration to flashlist
TMisiukiewicz 3fa6a58
display emojis correctly with flashlist
TMisiukiewicz 2928ac0
fix displaying headers
TMisiukiewicz 9a0b422
sticky headers in emoji picker
TMisiukiewicz 0fbc495
correctly display changing skin tone
TMisiukiewicz 6a6e929
scroll to offset
TMisiukiewicz 32504b6
scroll to offset
TMisiukiewicz 5dc95a5
display headers on native correctly
TMisiukiewicz 9b4207d
display scrollbar
TMisiukiewicz 79ac9ba
update getItemType
TMisiukiewicz 927a4f7
create separate file for getItemType
TMisiukiewicz cfd8066
update getItemType and list style
TMisiukiewicz 3c5d0e4
code review updates
TMisiukiewicz 18ea4ed
slice flags for operating system in asset
TMisiukiewicz 2e69a4f
extract updatePreferredSkinTone function
TMisiukiewicz 3a62259
create BaseEmojiPickerMenu
TMisiukiewicz 50ebdee
update BaseEmojiPickerMenu
TMisiukiewicz 0054ff6
code review updates
TMisiukiewicz 57b6f88
code review updates
TMisiukiewicz d5445c0
refactor EmojiPickerMenu for web
TMisiukiewicz 5bf55b9
implement useArrowKeyFocusManager
TMisiukiewicz 0162599
Revert "implement useArrowKeyFocusManager"
TMisiukiewicz 16e12fd
simplify implementation across platforms for emoji picker menu
TMisiukiewicz 4e60e58
get empty list component out of render loop
TMisiukiewicz f418753
code review updates
TMisiukiewicz 5063bab
Merge branch 'main' into feat/emojipicker-flashlist-migration
TMisiukiewicz cfd49dc
code review updates
TMisiukiewicz 46a24a6
Merge remote-tracking branch 'upstream/main' into feat/emojipicker-fl…
TMisiukiewicz 46177ef
add estimatedListSize to emoji picker menu
TMisiukiewicz 7c774f9
update getEmojiPickerListHeight
TMisiukiewicz 6b555d0
Merge branch 'main' into feat/emojipicker-flashlist-migration
TMisiukiewicz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
161 changes: 161 additions & 0 deletions
161
src/components/EmojiPicker/EmojiPickerMenu/BaseEmojiPickerMenu.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
import {FlashList} from '@shopify/flash-list'; | ||
import PropTypes from 'prop-types'; | ||
import React, {useMemo} from 'react'; | ||
import {StyleSheet, Text, View} from 'react-native'; | ||
import CategoryShortcutBar from '@components/EmojiPicker/CategoryShortcutBar'; | ||
import EmojiSkinToneList from '@components/EmojiPicker/EmojiSkinToneList'; | ||
import refPropTypes from '@components/refPropTypes'; | ||
import useLocalize from '@hooks/useLocalize'; | ||
import useThemeStyles from '@hooks/useThemeStyles'; | ||
import useWindowDimensions from '@hooks/useWindowDimensions'; | ||
import stylePropTypes from '@styles/stylePropTypes'; | ||
import CONST from '@src/CONST'; | ||
|
||
const emojiPropTypes = { | ||
/** The code of the item */ | ||
code: PropTypes.string.isRequired, | ||
roryabraham marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/** Whether the item is a header or not */ | ||
header: PropTypes.bool, | ||
|
||
/** Whether the item is a spacer or not */ | ||
spacer: PropTypes.bool, | ||
|
||
/** Types of an emoji - e.g. different skin types */ | ||
types: PropTypes.arrayOf(PropTypes.string), | ||
TMisiukiewicz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}; | ||
|
||
const propTypes = { | ||
/** Indicates if the emoji list is filtered or not */ | ||
isFiltered: PropTypes.bool.isRequired, | ||
|
||
/** Array of header emojis */ | ||
headerEmojis: PropTypes.arrayOf(PropTypes.shape(emojiPropTypes)).isRequired, | ||
|
||
/** Function to scroll to a specific header in the emoji list */ | ||
scrollToHeader: PropTypes.func.isRequired, | ||
|
||
/** Style to be applied to the list wrapper */ | ||
listWrapperStyle: stylePropTypes, | ||
|
||
/** Reference to the emoji list */ | ||
forwardedRef: refPropTypes, | ||
|
||
/** The data for the emoji list */ | ||
data: PropTypes.arrayOf(PropTypes.shape(emojiPropTypes)).isRequired, | ||
|
||
/** Function to render each item in the list */ | ||
renderItem: PropTypes.func.isRequired, | ||
|
||
/** Extra data to be passed to the list for re-rendering */ | ||
// eslint-disable-next-line react/forbid-prop-types | ||
extraData: PropTypes.any, | ||
|
||
/** Array of indices for the sticky headers */ | ||
stickyHeaderIndices: PropTypes.arrayOf(PropTypes.number), | ||
|
||
/** Whether the list should always bounce vertically */ | ||
alwaysBounceVertical: PropTypes.bool, | ||
}; | ||
|
||
const defaultProps = { | ||
listWrapperStyle: [], | ||
forwardedRef: () => {}, | ||
extraData: [], | ||
stickyHeaderIndices: [], | ||
alwaysBounceVertical: false, | ||
}; | ||
|
||
/** | ||
* Improves FlashList's recycling when there are different types of items | ||
* @param {Object} item | ||
* @returns {String} | ||
*/ | ||
const getItemType = (item) => { | ||
// item is undefined only when list is empty | ||
if (!item) { | ||
return; | ||
} | ||
|
||
if (item.name) { | ||
return CONST.EMOJI_PICKER_ITEM_TYPES.EMOJI; | ||
} | ||
if (item.header) { | ||
return CONST.EMOJI_PICKER_ITEM_TYPES.HEADER; | ||
} | ||
|
||
return CONST.EMOJI_PICKER_ITEM_TYPES.SPACER; | ||
}; | ||
|
||
/** | ||
* Return a unique key for each emoji item | ||
* | ||
* @param {Object} item | ||
* @param {Number} index | ||
* @returns {String} | ||
*/ | ||
const keyExtractor = (item, index) => `emoji_picker_${item.code}_${index}`; | ||
|
||
/** | ||
* Renders the list empty component | ||
* @returns {React.Component} | ||
*/ | ||
function ListEmptyComponent() { | ||
const styles = useThemeStyles(); | ||
const {translate} = useLocalize(); | ||
|
||
return <Text style={[styles.textLabel, styles.colorMuted]}>{translate('common.noResultsFound')}</Text>; | ||
} | ||
|
||
function BaseEmojiPickerMenu({headerEmojis, scrollToHeader, isFiltered, listWrapperStyle, forwardedRef, data, renderItem, stickyHeaderIndices, extraData, alwaysBounceVertical}) { | ||
const styles = useThemeStyles(); | ||
const {windowWidth, isSmallScreenWidth} = useWindowDimensions(); | ||
|
||
const flattenListWrapperStyle = useMemo(() => StyleSheet.flatten(listWrapperStyle), [listWrapperStyle]); | ||
|
||
return ( | ||
<> | ||
{!isFiltered && ( | ||
<CategoryShortcutBar | ||
headerEmojis={headerEmojis} | ||
onPress={scrollToHeader} | ||
/> | ||
)} | ||
<View style={listWrapperStyle}> | ||
<FlashList | ||
ref={forwardedRef} | ||
keyboardShouldPersistTaps="handled" | ||
data={data} | ||
renderItem={renderItem} | ||
keyExtractor={keyExtractor} | ||
numColumns={CONST.EMOJI_NUM_PER_ROW} | ||
stickyHeaderIndices={stickyHeaderIndices} | ||
ListEmptyComponent={ListEmptyComponent} | ||
alwaysBounceVertical={alwaysBounceVertical} | ||
estimatedItemSize={CONST.EMOJI_PICKER_ITEM_HEIGHT} | ||
estimatedListSize={{height: flattenListWrapperStyle.height, width: isSmallScreenWidth ? windowWidth : CONST.EMOJI_PICKER_SIZE.WIDTH}} | ||
contentContainerStyle={styles.ph4} | ||
extraData={extraData} | ||
getItemType={getItemType} | ||
/> | ||
</View> | ||
<EmojiSkinToneList /> | ||
</> | ||
); | ||
} | ||
|
||
BaseEmojiPickerMenu.propTypes = propTypes; | ||
BaseEmojiPickerMenu.defaultProps = defaultProps; | ||
BaseEmojiPickerMenu.displayName = 'BaseEmojiPickerMenu'; | ||
|
||
const BaseEmojiPickerMenuWithRef = React.forwardRef((props, ref) => ( | ||
<BaseEmojiPickerMenu | ||
// eslint-disable-next-line react/jsx-props-no-spreading | ||
{...props} | ||
forwardedRef={ref} | ||
/> | ||
)); | ||
|
||
BaseEmojiPickerMenuWithRef.displayName = 'BaseEmojiPickerMenuWithRef'; | ||
|
||
export default BaseEmojiPickerMenuWithRef; |
8 changes: 8 additions & 0 deletions
8
src/components/EmojiPicker/EmojiPickerMenu/emojiPickerMenuPropTypes.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import PropTypes from 'prop-types'; | ||
|
||
const emojiPickerMenuPropTypes = { | ||
/** Function to add the selected emoji to the main compose text input */ | ||
onEmojiSelected: PropTypes.func.isRequired, | ||
}; | ||
|
||
export default emojiPickerMenuPropTypes; |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@TMisiukiewicz This was implemented during the time you have worked on this PR but we have added the support for flag emojis on Windows in this issues and pr #31717
There was this issue raised here #33593, if you could comment on it so I can assign you and you could make a follow up to remove this Windows specific code. thanks!