feat: create search bar

This commit is contained in:
Jakub Grzywacz 2021-07-28 18:56:11 +02:00
parent c0cbef73c2
commit bc68650c6a
No known key found for this signature in database
GPG Key ID: 5BBB685871FF63C4
10 changed files with 106 additions and 8 deletions

11
src/assets/Search.tsx Normal file
View File

@ -0,0 +1,11 @@
import * as React from 'react';
import Svg, { FillProps, Path } from 'react-native-svg';
export default ({ fill }: FillProps) => (
<Svg width="23" height="23" viewBox="0 0 24 24" fill="none">
<Path
d="M20.71 19.29l-3.4-3.39A7.92 7.92 0 0 0 19 11a8 8 0 1 0-8 8 7.92 7.92 0 0 0 4.9-1.69l3.39 3.4a1 1 0 0 0 1.42 0 1 1 0 0 0 0-1.42zM5 11a6 6 0 1 1 6 6 6 6 0 0 1-6-6z"
fill={fill}
/>
</Svg>
);

View File

@ -23,6 +23,7 @@ export const Categories = ({ flatListRef, scrollNav }: CategoriesProps) => {
disabledCategory,
activeCategoryContainerColor,
categoryPosition,
searchPhrase,
} = React.useContext(KeyboardContext);
const handleScrollToCategory = React.useCallback(
@ -94,9 +95,11 @@ export const Categories = ({ flatListRef, scrollNav }: CategoriesProps) => {
<View style={[categoryPosition === 'floating' && styles.floating]}>
<View style={getStylesBasedOnPosition()}>
<FlatList
data={CATEGORIES_NAVIGATION.filter(
({ category }) => !disabledCategory.includes(category)
)}
data={CATEGORIES_NAVIGATION.filter(({ category }) => {
console.log(searchPhrase, 'search');
if (searchPhrase === '' && category === 'search') return false;
return !disabledCategory.includes(category);
})}
keyExtractor={(item) => item.category}
renderItem={rendarItem}
ItemSeparatorComponent={() => <View style={styles.separator} />}

View File

@ -12,6 +12,7 @@ import { EmojiCategory } from './EmojiCategory';
import { KeyboardContext } from '../contexts/KeyboardContext';
import { Categories } from './Categories';
import emojisByGroup from '../assets/emojis.json';
import { SearchBar } from './SearchBar';
export const EmojiStaticKeyboard = () => {
const { width } = useWindowDimensions();
@ -21,6 +22,9 @@ export const EmojiStaticKeyboard = () => {
onCategoryChangeFailed,
disabledCategory,
categoryPosition,
enableSearchBar,
searchPhrase,
setActiveCategoryIndex,
} = React.useContext(KeyboardContext);
const flatListRef = React.useRef<FlatList>(null);
@ -47,6 +51,29 @@ export const EmojiStaticKeyboard = () => {
}).start();
}, [activeCategoryIndex, scrollNav]);
const getData = React.useCallback(() => {
const enabledCategories = emojisByGroup.filter((category) => {
const title = category.title as CategoryTypes;
return !disabledCategory.includes(title);
});
enabledCategories.push({
title: 'search',
data: emojisByGroup
.map((group) => group.data)
.flat()
.filter((emoji) => {
return emoji.name.toLowerCase().includes(searchPhrase.toLowerCase());
}),
});
return enabledCategories;
}, [disabledCategory, searchPhrase]);
React.useEffect(() => {
if (searchPhrase !== '') {
flatListRef.current?.scrollToEnd();
setActiveCategoryIndex(getData().length - 1);
}
}, [getData, searchPhrase, setActiveCategoryIndex]);
return (
<View
style={[
@ -56,11 +83,10 @@ export const EmojiStaticKeyboard = () => {
containerStyles,
]}
>
{enableSearchBar && <SearchBar />}
<Animated.FlatList
data={emojisByGroup.filter((category) => {
const title = category.title as CategoryTypes;
return !disabledCategory.includes(title);
})}
data={getData()}
extraData={searchPhrase}
keyExtractor={(item: EmojisByCategory) => item.title}
renderItem={renderItem}
removeClippedSubviews={true}

View File

@ -8,6 +8,7 @@ import Smile from '../assets/Smile';
import Trees from '../assets/Trees';
import Ban from '../assets/Ban';
import Users from '../assets/Users';
import Search from '../assets/Search';
export const Icon = ({
iconName,
@ -40,6 +41,8 @@ export const Icon = ({
return <Ban fill={color()} />;
case 'Users':
return <Users fill={color()} />;
case 'Search':
return <Search fill={color()} />;
default:
return null;
}

View File

@ -0,0 +1,40 @@
import * as React from 'react';
import { View, StyleSheet, TextInput } from 'react-native';
import { KeyboardContext } from '../contexts/KeyboardContext';
export const SearchBar = () => {
const [search, setSearch] = React.useState('');
const { setSearchPhrase, translation } = React.useContext(KeyboardContext);
React.useEffect(() => {
console.log(search);
}, [search]);
const handleSearch = (text: string) => {
setSearch(text);
setSearchPhrase(text);
};
return (
<View style={styles.container}>
<TextInput
style={styles.input}
value={search}
onChangeText={handleSearch}
placeholder={translation.search}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
marginTop: 16,
},
input: {
paddingVertical: 8,
paddingHorizontal: 12,
marginHorizontal: 16,
borderRadius: 100,
borderWidth: 1,
borderColor: '#00000011',
},
});

View File

@ -38,12 +38,15 @@ export type KeyboardProps = {
translation?: CategoryTranslation;
disabledCategory?: CategoryTypes[];
categoryPosition?: CategoryPosition;
enableSearchBar?: boolean;
};
export type ContextValues = {
activeCategoryIndex: number;
setActiveCategoryIndex: (index: number) => void;
numberOfColumns: number;
width: number;
searchPhrase: string;
setSearchPhrase: (phrase: string) => void;
};
export const KeyboardContext = React.createContext<

View File

@ -37,6 +37,7 @@ export const defaultKeyboardContext: Required<KeyboardProps> = {
translation: en,
disabledCategory: [],
categoryPosition: 'floating',
enableSearchBar: false,
};
export const defaultKeyboardValues: ContextValues = {
@ -44,11 +45,14 @@ export const defaultKeyboardValues: ContextValues = {
setActiveCategoryIndex: () => {},
numberOfColumns: 5,
width: 0,
searchPhrase: '',
setSearchPhrase: (_phrase: string) => {},
};
export const KeyboardProvider: React.FC<ProviderProps> = React.memo((props) => {
const { width } = useWindowDimensions();
const [activeCategoryIndex, setActiveCategoryIndex] = React.useState(0);
const [searchPhrase, setSearchPhrase] = React.useState('');
const numberOfColumns = React.useRef<number>(
Math.floor(
width /
@ -60,6 +64,7 @@ export const KeyboardProvider: React.FC<ProviderProps> = React.memo((props) => {
);
React.useEffect(() => {
if (props.open) setActiveCategoryIndex(0);
setSearchPhrase('');
}, [props.open]);
const value: Required<KeyboardProps> & ContextValues = {
@ -70,6 +75,8 @@ export const KeyboardProvider: React.FC<ProviderProps> = React.memo((props) => {
setActiveCategoryIndex,
numberOfColumns: numberOfColumns.current,
width,
searchPhrase,
setSearchPhrase,
};
return (
<KeyboardContext.Provider value={value}>

View File

@ -10,5 +10,6 @@ export const en: CategoryTranslation = {
objects: 'Objects',
symbols: 'Symbols',
flags: 'Flags',
search: 'Search',
};
export default en;

View File

@ -10,5 +10,6 @@ const pl: CategoryTranslation = {
objects: 'Przedmioty',
symbols: 'Symbole',
flags: 'Flagi',
search: 'Szukaj',
};
export default pl;

View File

@ -19,7 +19,8 @@ export type CategoryTypes =
| 'activities'
| 'objects'
| 'symbols'
| 'flags';
| 'flags'
| 'search';
export type CategoryPosition = 'floating' | 'top' | 'bottom';
@ -33,6 +34,7 @@ export const CATEGORIES: CategoryTypes[] = [
'objects',
'symbols',
'flags',
'search',
];
export type CategoryNavigationItem = {
@ -54,6 +56,7 @@ export const CATEGORIES_NAVIGATION: CategoryNavigationItem[] = [
{ icon: 'Lightbulb', category: 'objects' },
{ icon: 'Ban', category: 'symbols' },
{ icon: 'Flag', category: 'flags' },
{ icon: 'Search', category: 'search' },
];
export type EmojisByCategory = {