Migrate to react-native-tab-view
This commit is contained in:
parent
0f51a3c5df
commit
359171ed03
|
@ -7,28 +7,30 @@ import { ITabBarProps } from './interfaces';
|
|||
import { isIOS } from '../../lib/methods/helpers';
|
||||
import { CustomIcon } from '../CustomIcon';
|
||||
|
||||
const TabBar = ({ activeTab, tabs, goToPage }: ITabBarProps): React.ReactElement => {
|
||||
const TabBar = ({ tabs, activeTab, onPress, showFrequentlyUsed }: ITabBarProps): React.ReactElement => {
|
||||
const { colors } = useTheme();
|
||||
|
||||
return (
|
||||
<View style={styles.tabsContainer}>
|
||||
{tabs?.map((tab, i) => (
|
||||
<Pressable
|
||||
key={tab}
|
||||
onPress={() => goToPage?.(i)}
|
||||
testID={`emoji-picker-tab-${tab}`}
|
||||
android_ripple={{ color: colors.bannerBackground }}
|
||||
style={({ pressed }: { pressed: boolean }) => [
|
||||
styles.tab,
|
||||
{
|
||||
backgroundColor: isIOS && pressed ? colors.bannerBackground : 'transparent'
|
||||
}
|
||||
]}
|
||||
>
|
||||
<CustomIcon name={tab} size={24} color={activeTab === i ? colors.tintColor : colors.auxiliaryTintColor} />
|
||||
<View style={activeTab === i ? [styles.activeTabLine, { backgroundColor: colors.tintColor }] : styles.tabLine} />
|
||||
</Pressable>
|
||||
))}
|
||||
{tabs?.map((tab, i) => {
|
||||
if (i === 0 && !showFrequentlyUsed) return null;
|
||||
return (
|
||||
<Pressable
|
||||
key={tab.key}
|
||||
onPress={() => onPress(tab.key)}
|
||||
testID={`emoji-picker-tab-${tab.key}`}
|
||||
android_ripple={{ color: colors.bannerBackground }}
|
||||
style={({ pressed }: { pressed: boolean }) => [
|
||||
styles.tab,
|
||||
{
|
||||
backgroundColor: isIOS && pressed ? colors.bannerBackground : 'transparent'
|
||||
}
|
||||
]}
|
||||
>
|
||||
<CustomIcon name={tab.key} size={24} color={activeTab === i ? colors.tintColor : colors.auxiliaryTintColor} />
|
||||
<View style={activeTab === i ? [styles.activeTabLine, { backgroundColor: colors.tintColor }] : styles.tabLine} />
|
||||
</Pressable>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,44 +1,59 @@
|
|||
const list = ['frequentlyUsed', 'custom', 'people', 'nature', 'food', 'activity', 'travel', 'objects', 'symbols', 'flags'];
|
||||
const tabs = [
|
||||
import { TIconsName } from '../CustomIcon';
|
||||
|
||||
export type IEmojiCategory =
|
||||
| 'frequentlyUsed'
|
||||
| 'custom'
|
||||
| 'people'
|
||||
| 'nature'
|
||||
| 'food'
|
||||
| 'activity'
|
||||
| 'travel'
|
||||
| 'objects'
|
||||
| 'symbols'
|
||||
| 'flags';
|
||||
const tabs: {
|
||||
key: TIconsName;
|
||||
title: IEmojiCategory;
|
||||
}[] = [
|
||||
{
|
||||
tabLabel: 'clock',
|
||||
category: list[0]
|
||||
key: 'clock',
|
||||
title: 'frequentlyUsed'
|
||||
},
|
||||
{
|
||||
tabLabel: 'rocket',
|
||||
category: list[1]
|
||||
key: 'rocket',
|
||||
title: 'custom'
|
||||
},
|
||||
{
|
||||
tabLabel: 'emoji',
|
||||
category: list[2]
|
||||
key: 'emoji',
|
||||
title: 'people'
|
||||
},
|
||||
{
|
||||
tabLabel: 'leaf',
|
||||
category: list[3]
|
||||
key: 'leaf',
|
||||
title: 'nature'
|
||||
},
|
||||
{
|
||||
tabLabel: 'burger',
|
||||
category: list[4]
|
||||
key: 'burger',
|
||||
title: 'food'
|
||||
},
|
||||
{
|
||||
tabLabel: 'basketball',
|
||||
category: list[5]
|
||||
key: 'basketball',
|
||||
title: 'activity'
|
||||
},
|
||||
{
|
||||
tabLabel: 'airplane',
|
||||
category: list[6]
|
||||
key: 'airplane',
|
||||
title: 'travel'
|
||||
},
|
||||
{
|
||||
tabLabel: 'lamp-bulb',
|
||||
category: list[7]
|
||||
key: 'lamp-bulb',
|
||||
title: 'objects'
|
||||
},
|
||||
{
|
||||
tabLabel: 'percentage',
|
||||
category: list[8]
|
||||
key: 'percentage',
|
||||
title: 'symbols'
|
||||
},
|
||||
{
|
||||
tabLabel: 'flag',
|
||||
category: list[9]
|
||||
key: 'flag',
|
||||
title: 'flags'
|
||||
}
|
||||
];
|
||||
export default { list, tabs };
|
||||
export default tabs;
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import React, { useMemo } from 'react';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { View } from 'react-native';
|
||||
import ScrollableTabView from 'react-native-scrollable-tab-view';
|
||||
import { TabView, SceneRendererProps, NavigationState } from 'react-native-tab-view';
|
||||
import { shallowEqual } from 'react-redux';
|
||||
|
||||
import TabBar from './TabBar';
|
||||
import EmojiCategory from './EmojiCategory';
|
||||
import Footer from './Footer';
|
||||
import styles from './styles';
|
||||
import categories from './categories';
|
||||
import categories, { IEmojiCategory } from './categories';
|
||||
import { emojisByCategory } from './emojis';
|
||||
import shortnameToUnicode from '../../lib/methods/helpers/shortnameToUnicode';
|
||||
import log from '../../lib/methods/helpers/log';
|
||||
|
@ -16,16 +16,18 @@ import { IEmoji, ICustomEmojis } from '../../definitions';
|
|||
import { useAppSelector } from '../../lib/hooks';
|
||||
import { IEmojiPickerProps, EventTypes } from './interfaces';
|
||||
import { useFrequentlyUsedEmoji, addFrequentlyUsed } from './frequentlyUsedEmojis';
|
||||
import { TIconsName } from '../CustomIcon';
|
||||
|
||||
const EmojiPicker = ({
|
||||
onItemClicked,
|
||||
tabEmojiStyle,
|
||||
isEmojiKeyboard = false,
|
||||
searching = false,
|
||||
searchedEmojis = []
|
||||
}: IEmojiPickerProps): React.ReactElement | null => {
|
||||
const { colors } = useTheme();
|
||||
const { frequentlyUsed, loaded } = useFrequentlyUsedEmoji();
|
||||
const [index, setIndex] = useState(0);
|
||||
const [routes] = useState(categories);
|
||||
|
||||
const baseUrl = useAppSelector(state => state.server?.server);
|
||||
const allCustomEmojis: ICustomEmojis = useAppSelector(state => state.customEmojis, shallowEqual);
|
||||
|
@ -62,14 +64,16 @@ const EmojiPicker = ({
|
|||
}
|
||||
};
|
||||
|
||||
const renderCategory = (category: keyof typeof emojisByCategory, i: number, label: string, tabsCount: number) => {
|
||||
const tabsCount = frequentlyUsed.length === 0 ? categories.length - 1 : categories.length;
|
||||
|
||||
const Category = React.memo(({ title }: { title: IEmojiCategory }) => {
|
||||
let emojis = [];
|
||||
if (i === 0) {
|
||||
if (title === 'frequentlyUsed') {
|
||||
emojis = frequentlyUsed;
|
||||
} else if (i === 1) {
|
||||
} else if (title === 'custom') {
|
||||
emojis = customEmojis;
|
||||
} else {
|
||||
emojis = emojisByCategory[category];
|
||||
emojis = emojisByCategory[title];
|
||||
}
|
||||
return (
|
||||
<EmojiCategory
|
||||
|
@ -77,18 +81,24 @@ const EmojiPicker = ({
|
|||
onEmojiSelected={(emoji: IEmoji | string) => handleEmojiSelect(emoji)}
|
||||
style={styles.categoryContainer}
|
||||
baseUrl={baseUrl}
|
||||
tabLabel={label}
|
||||
tabsCount={tabsCount}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
type Route = {
|
||||
key: string;
|
||||
title: string;
|
||||
};
|
||||
type State = NavigationState<Route>;
|
||||
const renderTabBar = (props: SceneRendererProps & { navigationState: State }) => (
|
||||
<TabBar tabs={categories} onPress={props.jumpTo} activeTab={index} showFrequentlyUsed={frequentlyUsed.length > 0} />
|
||||
);
|
||||
|
||||
if (!loaded) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const tabsCount = frequentlyUsed.length === 0 ? categories.tabs.length - 1 : categories.tabs.length;
|
||||
|
||||
return (
|
||||
<View style={styles.emojiPickerContainer}>
|
||||
{searching ? (
|
||||
|
@ -97,24 +107,24 @@ const EmojiPicker = ({
|
|||
onEmojiSelected={(emoji: IEmoji | string) => handleEmojiSelect(emoji)}
|
||||
style={styles.categoryContainer}
|
||||
baseUrl={baseUrl}
|
||||
tabLabel={'searching'}
|
||||
tabsCount={tabsCount}
|
||||
/>
|
||||
) : (
|
||||
<ScrollableTabView
|
||||
renderTabBar={() => <TabBar tabEmojiStyle={tabEmojiStyle} />}
|
||||
contentProps={{
|
||||
keyboardShouldPersistTaps: 'always',
|
||||
keyboardDismissMode: 'none'
|
||||
}}
|
||||
<TabView
|
||||
lazy
|
||||
navigationState={{ index, routes }}
|
||||
renderScene={({
|
||||
route
|
||||
}: {
|
||||
route: {
|
||||
key: TIconsName;
|
||||
title: IEmojiCategory;
|
||||
};
|
||||
}) => <Category key={route.key} title={route.title} />}
|
||||
onIndexChange={setIndex}
|
||||
style={{ backgroundColor: colors.focusedBackground }}
|
||||
>
|
||||
{categories.tabs.map((tab: any, i) =>
|
||||
i === 0 && frequentlyUsed.length === 0
|
||||
? null // when no frequentlyUsed don't show the tab
|
||||
: renderCategory(tab.category, i, tab.tabLabel, tabsCount)
|
||||
)}
|
||||
</ScrollableTabView>
|
||||
renderTabBar={renderTabBar}
|
||||
/>
|
||||
)}
|
||||
{isEmojiKeyboard && (
|
||||
<Footer
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import { StyleProp, TextStyle } from 'react-native';
|
||||
|
||||
import { TIconsName } from '../CustomIcon';
|
||||
import { IEmoji } from '../../definitions';
|
||||
|
||||
|
@ -11,7 +9,6 @@ export enum EventTypes {
|
|||
|
||||
export interface IEmojiPickerProps {
|
||||
onItemClicked: (event: EventTypes, emoji?: string, shortname?: string) => void;
|
||||
tabEmojiStyle?: StyleProp<TextStyle>;
|
||||
isEmojiKeyboard?: boolean;
|
||||
searching?: boolean;
|
||||
searchedEmojis?: (string | IEmoji)[];
|
||||
|
@ -23,8 +20,8 @@ export interface IFooterProps {
|
|||
}
|
||||
|
||||
export interface ITabBarProps {
|
||||
goToPage?: (page: number) => void;
|
||||
activeTab?: number;
|
||||
tabs?: TIconsName[];
|
||||
tabEmojiStyle: StyleProp<TextStyle>;
|
||||
tabs?: { key: TIconsName; title: string }[];
|
||||
onPress: (ket: string) => void;
|
||||
showFrequentlyUsed?: boolean;
|
||||
}
|
||||
|
|
|
@ -33,7 +33,6 @@ export interface IEmojiCategory {
|
|||
emojis: (IEmoji | string)[];
|
||||
onEmojiSelected: (emoji: IEmoji | string) => void;
|
||||
style: StyleProp<ImageStyle>;
|
||||
tabLabel: string;
|
||||
tabsCount: number;
|
||||
}
|
||||
|
||||
|
|
|
@ -105,6 +105,7 @@
|
|||
"react-native-notifications": "^4.2.4",
|
||||
"react-native-notifier": "1.6.1",
|
||||
"react-native-orientation-locker": "1.1.8",
|
||||
"react-native-pager-view": "^5.4.25",
|
||||
"react-native-picker-select": "^8.0.4",
|
||||
"react-native-platform-touchable": "1.1.1",
|
||||
"react-native-popover-view": "4.0.1",
|
||||
|
@ -118,6 +119,7 @@
|
|||
"react-native-simple-crypto": "RocketChat/react-native-simple-crypto#0.5.1",
|
||||
"react-native-slowlog": "^1.0.2",
|
||||
"react-native-svg": "^12.3.0",
|
||||
"react-native-tab-view": "^3.1.1",
|
||||
"react-native-ui-lib": "RocketChat/react-native-ui-lib",
|
||||
"react-native-vector-icons": "9.1.0",
|
||||
"react-native-webview": "10.3.2",
|
||||
|
|
10
yarn.lock
10
yarn.lock
|
@ -17096,6 +17096,11 @@ react-native-orientation-locker@1.1.8:
|
|||
resolved "https://registry.yarnpkg.com/react-native-orientation-locker/-/react-native-orientation-locker-1.1.8.tgz#45d1c9e002496b8d286ec8932d6e3e7d341f9c85"
|
||||
integrity sha512-+Vd7x6O/3zGqYIMXpeDlaw3ma074Dtnocm8ryT9v5SvaiEcWSzII4frPgXaUcc/MiCq4OWZ1JtVoyw75mdomQw==
|
||||
|
||||
react-native-pager-view@^5.4.25:
|
||||
version "5.4.25"
|
||||
resolved "https://registry.yarnpkg.com/react-native-pager-view/-/react-native-pager-view-5.4.25.tgz#cd639d5387a7f3d5581b55a33c5faa1cbc200f97"
|
||||
integrity sha512-3drrYwaLat2fYszymZe3nHMPASJ4aJMaxiejfA1V5SK3OygYmdtmV2u5prX7TnjueJzGSyyaCYEr2JlrRt4YPg==
|
||||
|
||||
react-native-picker-select@^8.0.4:
|
||||
version "8.0.4"
|
||||
resolved "https://registry.yarnpkg.com/react-native-picker-select/-/react-native-picker-select-8.0.4.tgz#3f7f1f42df69b06e7d2c10338288332a6c40fd10"
|
||||
|
@ -17217,6 +17222,11 @@ react-native-swipe-gestures@^1.0.5:
|
|||
resolved "https://registry.yarnpkg.com/react-native-swipe-gestures/-/react-native-swipe-gestures-1.0.5.tgz#a172cb0f3e7478ccd681fd36b8bfbcdd098bde7c"
|
||||
integrity sha512-Ns7Bn9H/Tyw278+5SQx9oAblDZ7JixyzeOczcBK8dipQk2pD7Djkcfnf1nB/8RErAmMLL9iXgW0QHqiII8AhKw==
|
||||
|
||||
react-native-tab-view@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/react-native-tab-view/-/react-native-tab-view-3.1.1.tgz#1f8d7a835ab4f5b1b1407ec8dddc1053b53fa3c6"
|
||||
integrity sha512-M5pRN6utQfytKWoKlKVzg5NbkYu308qNoW1khGTtEOTs1k14p2dHJ/BWOJoJYHKbPVUyZldbG9MFT7gUl4YHnw==
|
||||
|
||||
react-native-text-size@4.0.0-rc.1:
|
||||
version "4.0.0-rc.1"
|
||||
resolved "https://registry.yarnpkg.com/react-native-text-size/-/react-native-text-size-4.0.0-rc.1.tgz#1e048d345dd6a5a8e1269e0585c1a5948c478da5"
|
||||
|
|
Loading…
Reference in New Issue