mirror of
https://github.com/status-im/rn-emoji-keyboard.git
synced 2025-01-27 00:29:04 +00:00
refactor: code review fixes
This commit is contained in:
parent
9c121bfd34
commit
2da4255385
@ -15,7 +15,8 @@ import emojisByGroup from './assets/emojis.json';
|
||||
|
||||
export const EmojiKeyboard = () => {
|
||||
const { width } = useWindowDimensions();
|
||||
const ctx = React.useContext(KeyboardContext);
|
||||
const { activeCategoryIndex, containerStyles, onCategoryChangeFailed } =
|
||||
React.useContext(KeyboardContext);
|
||||
|
||||
const flatListRef = React.useRef<FlatList>(null);
|
||||
|
||||
@ -36,22 +37,20 @@ export const EmojiKeyboard = () => {
|
||||
);
|
||||
React.useEffect(() => {
|
||||
Animated.spring(scrollNav, {
|
||||
toValue: ctx.activeCategoryIndex * (28 + 9),
|
||||
toValue: activeCategoryIndex * (28 + 9),
|
||||
useNativeDriver: true,
|
||||
}).start();
|
||||
}, [ctx, scrollNav]);
|
||||
}, [activeCategoryIndex, scrollNav]);
|
||||
|
||||
return (
|
||||
<View
|
||||
style={[styles.container, styles.containerShadow, ctx.containerStyles]}
|
||||
>
|
||||
<View style={[styles.container, styles.containerShadow, containerStyles]}>
|
||||
<Animated.FlatList
|
||||
data={emojisByGroup}
|
||||
keyExtractor={(item: EmojisByCategory) => item.title}
|
||||
renderItem={renderItem}
|
||||
removeClippedSubviews={true}
|
||||
ref={flatListRef}
|
||||
onScrollToIndexFailed={() => {}}
|
||||
onScrollToIndexFailed={onCategoryChangeFailed}
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
pagingEnabled
|
||||
|
@ -22,6 +22,11 @@ export type KeyboardProps = {
|
||||
categoryColor?: string;
|
||||
activeCategoryColor?: string;
|
||||
categoryContainerColor?: string;
|
||||
onCategoryChangeFailed?: (info: {
|
||||
index: number;
|
||||
highestMeasuredFrameIndex: number;
|
||||
averageItemLength: number;
|
||||
}) => void;
|
||||
};
|
||||
export type ContextValues = {
|
||||
activeCategoryIndex: number;
|
||||
|
@ -27,6 +27,9 @@ export const defaultKeyboardContext: Required<KeyboardProps> = {
|
||||
categoryColor: '#000000',
|
||||
activeCategoryColor: '#005b96',
|
||||
categoryContainerColor: '#e3dbcd',
|
||||
onCategoryChangeFailed: (info) => {
|
||||
console.warn(info);
|
||||
},
|
||||
};
|
||||
|
||||
export const defaultKeyboardValues: ContextValues = {
|
||||
|
@ -1,7 +1,12 @@
|
||||
import * as React from 'react';
|
||||
import { View, Animated, StyleSheet, FlatList } from 'react-native';
|
||||
import { KeyboardContext } from '../KeyboardContext';
|
||||
import { CATEGORIES, CATEGORIES_NAVIGATION, CategoryTypes } from '../types';
|
||||
import {
|
||||
CATEGORIES,
|
||||
CATEGORIES_NAVIGATION,
|
||||
CategoryNavigationItem,
|
||||
CategoryTypes,
|
||||
} from '../types';
|
||||
import { CategoryItem } from './CategoryItem';
|
||||
|
||||
type CategoriesProps = {
|
||||
@ -10,7 +15,12 @@ type CategoriesProps = {
|
||||
};
|
||||
|
||||
export const Categories = ({ flatListRef, scrollNav }: CategoriesProps) => {
|
||||
const ctx = React.useContext(KeyboardContext);
|
||||
const {
|
||||
activeCategoryIndex,
|
||||
categoryContainerColor,
|
||||
onCategoryChangeFailed,
|
||||
} = React.useContext(KeyboardContext);
|
||||
|
||||
const handleScrollToCategory = React.useCallback(
|
||||
(category: CategoryTypes) => {
|
||||
flatListRef?.current?.scrollToIndex({
|
||||
@ -21,7 +31,7 @@ export const Categories = ({ flatListRef, scrollNav }: CategoriesProps) => {
|
||||
);
|
||||
|
||||
const rendarItem = React.useCallback(
|
||||
({ item, index }) => (
|
||||
({ item, index }: { item: CategoryNavigationItem; index: number }) => (
|
||||
<CategoryItem
|
||||
item={item}
|
||||
index={index}
|
||||
@ -48,10 +58,7 @@ export const Categories = ({ flatListRef, scrollNav }: CategoriesProps) => {
|
||||
return (
|
||||
<View style={styles.bottomBar}>
|
||||
<View
|
||||
style={[
|
||||
styles.navigation,
|
||||
{ backgroundColor: ctx.categoryContainerColor },
|
||||
]}
|
||||
style={[styles.navigation, { backgroundColor: categoryContainerColor }]}
|
||||
>
|
||||
<FlatList
|
||||
data={CATEGORIES_NAVIGATION}
|
||||
@ -60,10 +67,10 @@ export const Categories = ({ flatListRef, scrollNav }: CategoriesProps) => {
|
||||
ItemSeparatorComponent={() => <View style={styles.separator} />}
|
||||
scrollEnabled={false}
|
||||
horizontal={true}
|
||||
onScrollToIndexFailed={(e) => console.log(e)}
|
||||
onScrollToIndexFailed={onCategoryChangeFailed}
|
||||
ListHeaderComponent={activeIndicator}
|
||||
ListHeaderComponentStyle={styles.activeIndicatorContainer}
|
||||
extraData={ctx?.activeCategoryIndex}
|
||||
extraData={activeCategoryIndex}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
@ -1,11 +1,11 @@
|
||||
import * as React from 'react';
|
||||
import { View, StyleSheet, TouchableOpacity } from 'react-native';
|
||||
import { KeyboardContext } from '../KeyboardContext';
|
||||
import type { CategoryTypes } from '../types';
|
||||
import type { CategoryNavigationItem, CategoryTypes } from '../types';
|
||||
import { Icon } from './Icon';
|
||||
|
||||
type CategoryItemProps = {
|
||||
item: any;
|
||||
item: CategoryNavigationItem;
|
||||
index: number;
|
||||
handleScrollToCategory: (category: CategoryTypes) => void;
|
||||
};
|
||||
@ -15,21 +15,26 @@ export const CategoryItem = ({
|
||||
index,
|
||||
handleScrollToCategory,
|
||||
}: CategoryItemProps) => {
|
||||
const ctx = React.useContext(KeyboardContext);
|
||||
const {
|
||||
activeCategoryIndex,
|
||||
categoryColor,
|
||||
activeCategoryColor,
|
||||
setActiveCategoryIndex,
|
||||
} = React.useContext(KeyboardContext);
|
||||
|
||||
const handleSelect = () => {
|
||||
handleScrollToCategory(item.category);
|
||||
setActiveCategoryIndex(index);
|
||||
};
|
||||
|
||||
return (
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
handleScrollToCategory(item.category);
|
||||
ctx?.setActiveCategoryIndex(index);
|
||||
}}
|
||||
>
|
||||
<TouchableOpacity onPress={handleSelect}>
|
||||
<View style={styles.container}>
|
||||
<Icon
|
||||
iconName={item.icon}
|
||||
isActive={ctx?.activeCategoryIndex === index}
|
||||
normalColor={ctx.categoryColor}
|
||||
activeColor={ctx.activeCategoryColor}
|
||||
isActive={activeCategoryIndex === index}
|
||||
normalColor={categoryColor}
|
||||
activeColor={activeCategoryColor}
|
||||
/>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
|
@ -14,20 +14,24 @@ const emptyEmoji = {
|
||||
emoji_version: '0',
|
||||
};
|
||||
|
||||
export const EmojiCategory = ({ item }: { item: EmojisByCategory }) => {
|
||||
export const EmojiCategory = ({
|
||||
item: { title, data },
|
||||
}: {
|
||||
item: EmojisByCategory;
|
||||
}) => {
|
||||
const { onEmojiSelected, emojiSize, ...ctx } =
|
||||
React.useContext(KeyboardContext);
|
||||
|
||||
const [empty, setEmpty] = React.useState<EmojiType[]>([]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (item.data.length % ctx.numberOfColumns) {
|
||||
if (data.length % ctx.numberOfColumns) {
|
||||
const fillWithEmpty = new Array(
|
||||
ctx.numberOfColumns - (item.data.length % ctx.numberOfColumns)
|
||||
ctx.numberOfColumns - (data.length % ctx.numberOfColumns)
|
||||
).fill(emptyEmoji);
|
||||
setEmpty(fillWithEmpty);
|
||||
}
|
||||
}, [ctx.numberOfColumns, item]);
|
||||
}, [ctx.numberOfColumns, data]);
|
||||
|
||||
const getItemLayout = (_: EmojiType[] | null | undefined, index: number) => ({
|
||||
length: emojiSize ? emojiSize : 0,
|
||||
@ -49,12 +53,10 @@ export const EmojiCategory = ({ item }: { item: EmojisByCategory }) => {
|
||||
return (
|
||||
<View style={[styles.container, { width: ctx.width }]}>
|
||||
{!ctx.hideHeader && (
|
||||
<Text style={[styles.sectionTitle, ctx.headerStyles]}>
|
||||
{item.title}
|
||||
</Text>
|
||||
<Text style={[styles.sectionTitle, ctx.headerStyles]}>{title}</Text>
|
||||
)}
|
||||
<FlatList
|
||||
data={[...item.data, ...empty]}
|
||||
data={[...data, ...empty]}
|
||||
keyExtractor={(emoji) => emoji.name}
|
||||
numColumns={ctx.numberOfColumns}
|
||||
renderItem={renderItem}
|
||||
|
@ -75,5 +75,6 @@ const styles = StyleSheet.create({
|
||||
shadowOpacity: 0.15,
|
||||
shadowOffset: { width: 0, height: 0 },
|
||||
shadowRadius: 5,
|
||||
elevation: 10,
|
||||
},
|
||||
});
|
||||
|
@ -11,15 +11,11 @@ export class SingleEmoji extends React.Component<{
|
||||
return false;
|
||||
}
|
||||
render() {
|
||||
const { item, emojiSize, onPress } = this.props;
|
||||
return (
|
||||
<TouchableOpacity
|
||||
onPress={() => this.props.onPress(this.props.item)}
|
||||
style={styles.container}
|
||||
>
|
||||
<TouchableOpacity onPress={() => onPress(item)} style={styles.container}>
|
||||
<View style={styles.iconContainer}>
|
||||
<Text style={{ fontSize: this.props.emojiSize }}>
|
||||
{this.props.item.emoji}
|
||||
</Text>
|
||||
<Text style={{ fontSize: emojiSize }}>{item.emoji}</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
|
14
src/types.ts
14
src/types.ts
@ -30,7 +30,7 @@ export const CATEGORIES: CategoryTypes[] = [
|
||||
'Flags',
|
||||
];
|
||||
|
||||
type CategoryNavigationItem = {
|
||||
export type CategoryNavigationItem = {
|
||||
icon: string;
|
||||
category: CategoryTypes;
|
||||
};
|
||||
@ -47,18 +47,6 @@ export const CATEGORIES_NAVIGATION: CategoryNavigationItem[] = [
|
||||
{ icon: 'Flag', category: 'Flags' },
|
||||
];
|
||||
|
||||
// export const CATEGORIES_NAVIGATION: CategoryNavigationItem[] = [
|
||||
// { icon: '😀', category: 'Smileys & Emotion' },
|
||||
// { icon: '👋', category: 'People & Body' },
|
||||
// { icon: '🐵', category: 'Animals & Nature' },
|
||||
// { icon: '🍇', category: 'Food & Drink' },
|
||||
// { icon: '🌍', category: 'Travel & Places' },
|
||||
// { icon: '🎃', category: 'Activities' },
|
||||
// { icon: '👓', category: 'Objects' },
|
||||
// { icon: '🏧', category: 'Symbols' },
|
||||
// { icon: '🏁', category: 'Flags' },
|
||||
// ];
|
||||
|
||||
export type EmojisByCategory = {
|
||||
title: CategoryTypes;
|
||||
data: EmojiType[];
|
||||
|
Loading…
x
Reference in New Issue
Block a user