chore: change prettier config (#19)
This commit is contained in:
parent
c4a8ed36fc
commit
f68fcf720f
|
@ -1,3 +1,3 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
presets: ['module:metro-react-native-babel-preset'],
|
presets: ['module:metro-react-native-babel-preset'],
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
const path = require('path');
|
const path = require('path')
|
||||||
const pak = require('../package.json');
|
const pak = require('../package.json')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
presets: ['module:metro-react-native-babel-preset'],
|
presets: ['module:metro-react-native-babel-preset'],
|
||||||
|
@ -14,4 +14,4 @@ module.exports = {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { AppRegistry } from 'react-native';
|
import { AppRegistry } from 'react-native'
|
||||||
import App from './src/App';
|
import App from './src/App'
|
||||||
import { name as appName } from './app.json';
|
import { name as appName } from './app.json'
|
||||||
|
|
||||||
AppRegistry.registerComponent(appName, () => App);
|
AppRegistry.registerComponent(appName, () => App)
|
||||||
|
|
|
@ -494,8 +494,8 @@ SPEC CHECKSUMS:
|
||||||
Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9
|
Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9
|
||||||
Flipper-RSocket: d9d9ade67cbecf6ac10730304bf5607266dd2541
|
Flipper-RSocket: d9d9ade67cbecf6ac10730304bf5607266dd2541
|
||||||
FlipperKit: 57764956d2f0f972c1af5075a9c8f05ca5b12349
|
FlipperKit: 57764956d2f0f972c1af5075a9c8f05ca5b12349
|
||||||
Folly: b73c3869541e86821df3c387eb0af5f65addfab4
|
Folly: aeb27d02cdff07ca01f8a8a5a6dd5bcaf6be6f70
|
||||||
glog: 40a13f7840415b9a77023fbcae0f1e6f43192af3
|
glog: 2ad46e202fbaa5641fceb4b2af37dcd88fd8762d
|
||||||
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
|
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
|
||||||
OpenSSL-Universal: 1aa4f6a6ee7256b83db99ec1ccdaa80d10f9af9b
|
OpenSSL-Universal: 1aa4f6a6ee7256b83db99ec1ccdaa80d10f9af9b
|
||||||
RCTRequired: 082f10cd3f905d6c124597fd1c14f6f2655ff65e
|
RCTRequired: 082f10cd3f905d6c124597fd1c14f6f2655ff65e
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
const path = require('path');
|
const path = require('path')
|
||||||
const blacklist = require('metro-config/src/defaults/blacklist');
|
const blacklist = require('metro-config/src/defaults/blacklist')
|
||||||
const escape = require('escape-string-regexp');
|
const escape = require('escape-string-regexp')
|
||||||
const pak = require('../package.json');
|
const pak = require('../package.json')
|
||||||
|
|
||||||
const root = path.resolve(__dirname, '..');
|
const root = path.resolve(__dirname, '..')
|
||||||
|
|
||||||
const modules = Object.keys({
|
const modules = Object.keys({
|
||||||
...pak.peerDependencies,
|
...pak.peerDependencies,
|
||||||
});
|
})
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
projectRoot: __dirname,
|
projectRoot: __dirname,
|
||||||
|
@ -17,15 +17,12 @@ module.exports = {
|
||||||
// So we blacklist them at the root, and alias them to the versions in example's node_modules
|
// So we blacklist them at the root, and alias them to the versions in example's node_modules
|
||||||
resolver: {
|
resolver: {
|
||||||
blacklistRE: blacklist(
|
blacklistRE: blacklist(
|
||||||
modules.map(
|
modules.map((m) => new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`))
|
||||||
(m) =>
|
|
||||||
new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`)
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
|
|
||||||
extraNodeModules: modules.reduce((acc, name) => {
|
extraNodeModules: modules.reduce((acc, name) => {
|
||||||
acc[name] = path.join(__dirname, 'node_modules', name);
|
acc[name] = path.join(__dirname, 'node_modules', name)
|
||||||
return acc;
|
return acc
|
||||||
}, {}),
|
}, {}),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -37,4 +34,4 @@ module.exports = {
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
import 'react-native-gesture-handler';
|
import 'react-native-gesture-handler'
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import { NavigationContainer } from '@react-navigation/native';
|
import { NavigationContainer } from '@react-navigation/native'
|
||||||
import { createStackNavigator } from '@react-navigation/stack';
|
import { createStackNavigator } from '@react-navigation/stack'
|
||||||
import Examples from './Examples/Examples';
|
import Examples from './Examples/Examples'
|
||||||
import Basic from './Basic/Basic';
|
import Basic from './Basic/Basic'
|
||||||
import Dark from './Dark/Dark';
|
import Dark from './Dark/Dark'
|
||||||
import Translated from './Translated/Translated';
|
import Translated from './Translated/Translated'
|
||||||
import DisabledCategories from './DisabledCategories/DisabledCategories';
|
import DisabledCategories from './DisabledCategories/DisabledCategories'
|
||||||
import StaticModal from './StaticModal/StaticModal';
|
import StaticModal from './StaticModal/StaticModal'
|
||||||
import Static from './Static/Static';
|
import Static from './Static/Static'
|
||||||
import EnableRecently from './EnableRecently/EnableRecently';
|
import EnableRecently from './EnableRecently/EnableRecently'
|
||||||
import TopCategory from './TopCategory/TopCategory';
|
import TopCategory from './TopCategory/TopCategory'
|
||||||
import BottomCategory from './BottomCategory/BottomCategory';
|
import BottomCategory from './BottomCategory/BottomCategory'
|
||||||
import SearchBar from './SearchBar/SearchBar';
|
import SearchBar from './SearchBar/SearchBar'
|
||||||
|
|
||||||
const Stack = createStackNavigator();
|
const Stack = createStackNavigator()
|
||||||
export default () => {
|
export default () => {
|
||||||
return (
|
return (
|
||||||
<NavigationContainer>
|
<NavigationContainer>
|
||||||
|
@ -27,13 +27,10 @@ export default () => {
|
||||||
<Stack.Screen name="TopCategory" component={TopCategory} />
|
<Stack.Screen name="TopCategory" component={TopCategory} />
|
||||||
<Stack.Screen name="BottomCategory" component={BottomCategory} />
|
<Stack.Screen name="BottomCategory" component={BottomCategory} />
|
||||||
<Stack.Screen name="Translated" component={Translated} />
|
<Stack.Screen name="Translated" component={Translated} />
|
||||||
<Stack.Screen
|
<Stack.Screen name="DisabledCategories" component={DisabledCategories} />
|
||||||
name="DisabledCategories"
|
|
||||||
component={DisabledCategories}
|
|
||||||
/>
|
|
||||||
<Stack.Screen name="StaticModal" component={StaticModal} />
|
<Stack.Screen name="StaticModal" component={StaticModal} />
|
||||||
<Stack.Screen name="Static" component={Static} />
|
<Stack.Screen name="Static" component={Static} />
|
||||||
</Stack.Navigator>
|
</Stack.Navigator>
|
||||||
</NavigationContainer>
|
</NavigationContainer>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import { StyleSheet, Text, TouchableOpacity } from 'react-native';
|
import { StyleSheet, Text, TouchableOpacity } from 'react-native'
|
||||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
import { SafeAreaView } from 'react-native-safe-area-context'
|
||||||
import EmojiPicker from 'rn-emoji-keyboard';
|
import EmojiPicker from 'rn-emoji-keyboard'
|
||||||
import type { EmojiType } from 'src/types';
|
import type { EmojiType } from 'src/types'
|
||||||
|
|
||||||
const Basic = () => {
|
const Basic = () => {
|
||||||
const [result, setResult] = React.useState<string>();
|
const [result, setResult] = React.useState<string>()
|
||||||
const [isModalOpen, setIsModalOpen] = React.useState<boolean>(false);
|
const [isModalOpen, setIsModalOpen] = React.useState<boolean>(false)
|
||||||
|
|
||||||
const handlePick = (emoji: EmojiType) => {
|
const handlePick = (emoji: EmojiType) => {
|
||||||
console.log(emoji);
|
console.log(emoji)
|
||||||
setResult(emoji.emoji);
|
setResult(emoji.emoji)
|
||||||
setIsModalOpen((prev) => !prev);
|
setIsModalOpen((prev) => !prev)
|
||||||
};
|
}
|
||||||
return (
|
return (
|
||||||
<SafeAreaView style={styles.container}>
|
<SafeAreaView style={styles.container}>
|
||||||
<Text style={styles.text}>Result: {result}</Text>
|
<Text style={styles.text}>Result: {result}</Text>
|
||||||
|
@ -26,8 +26,8 @@ const Basic = () => {
|
||||||
onClose={() => setIsModalOpen(false)}
|
onClose={() => setIsModalOpen(false)}
|
||||||
/>
|
/>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
|
@ -38,6 +38,6 @@ const styles = StyleSheet.create({
|
||||||
margin: 64,
|
margin: 64,
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
||||||
export default Basic;
|
export default Basic
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import { StyleSheet, Text, TouchableOpacity } from 'react-native';
|
import { StyleSheet, Text, TouchableOpacity } from 'react-native'
|
||||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
import { SafeAreaView } from 'react-native-safe-area-context'
|
||||||
import EmojiPicker from 'rn-emoji-keyboard';
|
import EmojiPicker from 'rn-emoji-keyboard'
|
||||||
import type { EmojiType } from 'src/types';
|
import type { EmojiType } from 'src/types'
|
||||||
|
|
||||||
const BottomCategory = () => {
|
const BottomCategory = () => {
|
||||||
const [result, setResult] = React.useState<string>();
|
const [result, setResult] = React.useState<string>()
|
||||||
const [isModalOpen, setIsModalOpen] = React.useState<boolean>(false);
|
const [isModalOpen, setIsModalOpen] = React.useState<boolean>(false)
|
||||||
|
|
||||||
const handlePick = (emoji: EmojiType) => {
|
const handlePick = (emoji: EmojiType) => {
|
||||||
setResult(emoji.emoji);
|
setResult(emoji.emoji)
|
||||||
setIsModalOpen((prev) => !prev);
|
setIsModalOpen((prev) => !prev)
|
||||||
};
|
}
|
||||||
return (
|
return (
|
||||||
<SafeAreaView style={styles.container}>
|
<SafeAreaView style={styles.container}>
|
||||||
<Text style={styles.text}>Result: {result}</Text>
|
<Text style={styles.text}>Result: {result}</Text>
|
||||||
|
@ -26,8 +26,8 @@ const BottomCategory = () => {
|
||||||
categoryPosition="bottom"
|
categoryPosition="bottom"
|
||||||
/>
|
/>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
|
@ -38,6 +38,6 @@ const styles = StyleSheet.create({
|
||||||
margin: 64,
|
margin: 64,
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
||||||
export default BottomCategory;
|
export default BottomCategory
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import { StyleSheet, Text, TouchableOpacity } from 'react-native';
|
import { StyleSheet, Text, TouchableOpacity } from 'react-native'
|
||||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
import { SafeAreaView } from 'react-native-safe-area-context'
|
||||||
import EmojiPicker from 'rn-emoji-keyboard';
|
import EmojiPicker from 'rn-emoji-keyboard'
|
||||||
import type { EmojiType } from 'src/types';
|
import type { EmojiType } from 'src/types'
|
||||||
|
|
||||||
const Dark = () => {
|
const Dark = () => {
|
||||||
const [result, setResult] = React.useState<string>();
|
const [result, setResult] = React.useState<string>()
|
||||||
const [isModalOpen, setIsModalOpen] = React.useState<boolean>(false);
|
const [isModalOpen, setIsModalOpen] = React.useState<boolean>(false)
|
||||||
|
|
||||||
const handlePick = (emoji: EmojiType) => {
|
const handlePick = (emoji: EmojiType) => {
|
||||||
console.log(emoji);
|
console.log(emoji)
|
||||||
setResult(emoji.emoji);
|
setResult(emoji.emoji)
|
||||||
setIsModalOpen((prev) => !prev);
|
setIsModalOpen((prev) => !prev)
|
||||||
};
|
}
|
||||||
return (
|
return (
|
||||||
<SafeAreaView style={styles.container}>
|
<SafeAreaView style={styles.container}>
|
||||||
<Text style={styles.text}>Result: {result}</Text>
|
<Text style={styles.text}>Result: {result}</Text>
|
||||||
|
@ -34,8 +34,8 @@ const Dark = () => {
|
||||||
headerStyles={styles.headerStyles}
|
headerStyles={styles.headerStyles}
|
||||||
/>
|
/>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
|
@ -58,6 +58,6 @@ const styles = StyleSheet.create({
|
||||||
color: '#fff',
|
color: '#fff',
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
||||||
export default Dark;
|
export default Dark
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import { StyleSheet, Text, TouchableOpacity } from 'react-native';
|
import { StyleSheet, Text, TouchableOpacity } from 'react-native'
|
||||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
import { SafeAreaView } from 'react-native-safe-area-context'
|
||||||
import EmojiPicker from 'rn-emoji-keyboard';
|
import EmojiPicker from 'rn-emoji-keyboard'
|
||||||
import type { EmojiType } from 'src/types';
|
import type { EmojiType } from 'src/types'
|
||||||
|
|
||||||
const DisabledCategories = () => {
|
const DisabledCategories = () => {
|
||||||
const [result, setResult] = React.useState<string>();
|
const [result, setResult] = React.useState<string>()
|
||||||
const [isModalOpen, setIsModalOpen] = React.useState<boolean>(false);
|
const [isModalOpen, setIsModalOpen] = React.useState<boolean>(false)
|
||||||
|
|
||||||
const handlePick = (emoji: EmojiType) => {
|
const handlePick = (emoji: EmojiType) => {
|
||||||
console.log(emoji);
|
console.log(emoji)
|
||||||
setResult(emoji.emoji);
|
setResult(emoji.emoji)
|
||||||
setIsModalOpen((prev) => !prev);
|
setIsModalOpen((prev) => !prev)
|
||||||
};
|
}
|
||||||
return (
|
return (
|
||||||
<SafeAreaView style={styles.container}>
|
<SafeAreaView style={styles.container}>
|
||||||
<Text style={styles.text}>Result: {result}</Text>
|
<Text style={styles.text}>Result: {result}</Text>
|
||||||
|
@ -27,8 +27,8 @@ const DisabledCategories = () => {
|
||||||
disabledCategory={['activities', 'flags', 'objects', 'symbols']}
|
disabledCategory={['activities', 'flags', 'objects', 'symbols']}
|
||||||
/>
|
/>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
|
@ -39,6 +39,6 @@ const styles = StyleSheet.create({
|
||||||
margin: 64,
|
margin: 64,
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
||||||
export default DisabledCategories;
|
export default DisabledCategories
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import { StyleSheet, Text, TouchableOpacity } from 'react-native';
|
import { StyleSheet, Text, TouchableOpacity } from 'react-native'
|
||||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
import { SafeAreaView } from 'react-native-safe-area-context'
|
||||||
import EmojiPicker from 'rn-emoji-keyboard';
|
import EmojiPicker from 'rn-emoji-keyboard'
|
||||||
import type { EmojiType } from 'src/types';
|
import type { EmojiType } from 'src/types'
|
||||||
|
|
||||||
const EnableRecently = () => {
|
const EnableRecently = () => {
|
||||||
const [result, setResult] = React.useState<string>();
|
const [result, setResult] = React.useState<string>()
|
||||||
const [isModalOpen, setIsModalOpen] = React.useState<boolean>(false);
|
const [isModalOpen, setIsModalOpen] = React.useState<boolean>(false)
|
||||||
|
|
||||||
const handlePick = (emoji: EmojiType) => {
|
const handlePick = (emoji: EmojiType) => {
|
||||||
console.log(emoji);
|
console.log(emoji)
|
||||||
setResult(emoji.emoji);
|
setResult(emoji.emoji)
|
||||||
setIsModalOpen((prev) => !prev);
|
setIsModalOpen((prev) => !prev)
|
||||||
};
|
}
|
||||||
return (
|
return (
|
||||||
<SafeAreaView style={styles.container}>
|
<SafeAreaView style={styles.container}>
|
||||||
<Text style={styles.text}>Result: {result}</Text>
|
<Text style={styles.text}>Result: {result}</Text>
|
||||||
|
@ -27,8 +27,8 @@ const EnableRecently = () => {
|
||||||
enableRecentlyUsed
|
enableRecentlyUsed
|
||||||
/>
|
/>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
|
@ -39,6 +39,6 @@ const styles = StyleSheet.create({
|
||||||
margin: 64,
|
margin: 64,
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
||||||
export default EnableRecently;
|
export default EnableRecently
|
||||||
|
|
|
@ -1,23 +1,23 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import { View, Button } from 'react-native';
|
import { View, Button } from 'react-native'
|
||||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
import { SafeAreaView } from 'react-native-safe-area-context'
|
||||||
import type { StackScreenProps } from '@react-navigation/stack';
|
import type { StackScreenProps } from '@react-navigation/stack'
|
||||||
|
|
||||||
type RootStackParamList = {
|
type RootStackParamList = {
|
||||||
Examples: undefined;
|
Examples: undefined
|
||||||
Basic: undefined;
|
Basic: undefined
|
||||||
Dark: undefined;
|
Dark: undefined
|
||||||
Translated: undefined;
|
Translated: undefined
|
||||||
DisabledCategories: undefined;
|
DisabledCategories: undefined
|
||||||
StaticModal: undefined;
|
StaticModal: undefined
|
||||||
Static: undefined;
|
Static: undefined
|
||||||
EnableRecently: undefined;
|
EnableRecently: undefined
|
||||||
TopCategory: undefined;
|
TopCategory: undefined
|
||||||
BottomCategory: undefined;
|
BottomCategory: undefined
|
||||||
SearchBar: undefined;
|
SearchBar: undefined
|
||||||
};
|
}
|
||||||
|
|
||||||
type Props = StackScreenProps<RootStackParamList, 'Examples'>;
|
type Props = StackScreenProps<RootStackParamList, 'Examples'>
|
||||||
|
|
||||||
const Examples = ({ navigation }: Props) => {
|
const Examples = ({ navigation }: Props) => {
|
||||||
return (
|
return (
|
||||||
|
@ -25,10 +25,7 @@ const Examples = ({ navigation }: Props) => {
|
||||||
<View>
|
<View>
|
||||||
<Button title="Basic" onPress={() => navigation.navigate('Basic')} />
|
<Button title="Basic" onPress={() => navigation.navigate('Basic')} />
|
||||||
<Button title="Dark" onPress={() => navigation.navigate('Dark')} />
|
<Button title="Dark" onPress={() => navigation.navigate('Dark')} />
|
||||||
<Button
|
<Button title="Translated" onPress={() => navigation.navigate('Translated')} />
|
||||||
title="Translated"
|
|
||||||
onPress={() => navigation.navigate('Translated')}
|
|
||||||
/>
|
|
||||||
<Button
|
<Button
|
||||||
title="Disabled Categories"
|
title="Disabled Categories"
|
||||||
onPress={() => navigation.navigate('DisabledCategories')}
|
onPress={() => navigation.navigate('DisabledCategories')}
|
||||||
|
@ -37,28 +34,16 @@ const Examples = ({ navigation }: Props) => {
|
||||||
title="Static Modal (wihtout knob)"
|
title="Static Modal (wihtout knob)"
|
||||||
onPress={() => navigation.navigate('StaticModal')}
|
onPress={() => navigation.navigate('StaticModal')}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button title="Static Component" onPress={() => navigation.navigate('Static')} />
|
||||||
title="Static Component"
|
|
||||||
onPress={() => navigation.navigate('Static')}
|
|
||||||
/>
|
|
||||||
<Button
|
<Button
|
||||||
title="Enable recently used"
|
title="Enable recently used"
|
||||||
onPress={() => navigation.navigate('EnableRecently')}
|
onPress={() => navigation.navigate('EnableRecently')}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button title="Category Top" onPress={() => navigation.navigate('TopCategory')} />
|
||||||
title="Category Top"
|
<Button title="Category Bottom" onPress={() => navigation.navigate('BottomCategory')} />
|
||||||
onPress={() => navigation.navigate('TopCategory')}
|
<Button title="Search Bar" onPress={() => navigation.navigate('SearchBar')} />
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
title="Category Bottom"
|
|
||||||
onPress={() => navigation.navigate('BottomCategory')}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
title="Search Bar"
|
|
||||||
onPress={() => navigation.navigate('SearchBar')}
|
|
||||||
/>
|
|
||||||
</View>
|
</View>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
export default Examples;
|
export default Examples
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import { StyleSheet, Text, TouchableOpacity } from 'react-native';
|
import { StyleSheet, Text, TouchableOpacity } from 'react-native'
|
||||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
import { SafeAreaView } from 'react-native-safe-area-context'
|
||||||
import EmojiPicker from 'rn-emoji-keyboard';
|
import EmojiPicker from 'rn-emoji-keyboard'
|
||||||
import type { EmojiType } from 'src/types';
|
import type { EmojiType } from 'src/types'
|
||||||
|
|
||||||
const SearchBar = () => {
|
const SearchBar = () => {
|
||||||
const [result, setResult] = React.useState<string>();
|
const [result, setResult] = React.useState<string>()
|
||||||
const [isModalOpen, setIsModalOpen] = React.useState<boolean>(false);
|
const [isModalOpen, setIsModalOpen] = React.useState<boolean>(false)
|
||||||
|
|
||||||
const handlePick = (emoji: EmojiType) => {
|
const handlePick = (emoji: EmojiType) => {
|
||||||
console.log(emoji);
|
console.log(emoji)
|
||||||
setResult(emoji.emoji);
|
setResult(emoji.emoji)
|
||||||
setIsModalOpen((prev) => !prev);
|
setIsModalOpen((prev) => !prev)
|
||||||
};
|
}
|
||||||
return (
|
return (
|
||||||
<SafeAreaView style={styles.container}>
|
<SafeAreaView style={styles.container}>
|
||||||
<Text style={styles.text}>Result: {result}</Text>
|
<Text style={styles.text}>Result: {result}</Text>
|
||||||
|
@ -27,8 +27,8 @@ const SearchBar = () => {
|
||||||
enableSearchBar
|
enableSearchBar
|
||||||
/>
|
/>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
|
@ -39,6 +39,6 @@ const styles = StyleSheet.create({
|
||||||
margin: 64,
|
margin: 64,
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
||||||
export default SearchBar;
|
export default SearchBar
|
||||||
|
|
|
@ -1,29 +1,26 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import { StyleSheet, Text, View } from 'react-native';
|
import { StyleSheet, Text, View } from 'react-native'
|
||||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
import { SafeAreaView } from 'react-native-safe-area-context'
|
||||||
import { EmojiKeyboard } from 'rn-emoji-keyboard';
|
import { EmojiKeyboard } from 'rn-emoji-keyboard'
|
||||||
import type { EmojiType } from 'src/types';
|
import type { EmojiType } from 'src/types'
|
||||||
|
|
||||||
const Static = () => {
|
const Static = () => {
|
||||||
const [result, setResult] = React.useState<string>();
|
const [result, setResult] = React.useState<string>()
|
||||||
|
|
||||||
const handlePick = (emoji: EmojiType) => {
|
const handlePick = (emoji: EmojiType) => {
|
||||||
setResult(emoji.emoji);
|
setResult(emoji.emoji)
|
||||||
};
|
}
|
||||||
return (
|
return (
|
||||||
<SafeAreaView style={styles.container}>
|
<SafeAreaView style={styles.container}>
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<Text style={styles.text}>Result: {result}</Text>
|
<Text style={styles.text}>Result: {result}</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<EmojiKeyboard
|
<EmojiKeyboard onEmojiSelected={handlePick} containerStyles={styles.keyboardContainer} />
|
||||||
onEmojiSelected={handlePick}
|
|
||||||
containerStyles={styles.keyboardContainer}
|
|
||||||
/>
|
|
||||||
</View>
|
</View>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
|
@ -37,6 +34,6 @@ const styles = StyleSheet.create({
|
||||||
keyboardContainer: {
|
keyboardContainer: {
|
||||||
borderRadius: 0,
|
borderRadius: 0,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
||||||
export default Static;
|
export default Static
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import { StyleSheet, Text, TouchableOpacity } from 'react-native';
|
import { StyleSheet, Text, TouchableOpacity } from 'react-native'
|
||||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
import { SafeAreaView } from 'react-native-safe-area-context'
|
||||||
import EmojiPicker from 'rn-emoji-keyboard';
|
import EmojiPicker from 'rn-emoji-keyboard'
|
||||||
import type { EmojiType } from 'src/types';
|
import type { EmojiType } from 'src/types'
|
||||||
|
|
||||||
const StaticModal = () => {
|
const StaticModal = () => {
|
||||||
const [result, setResult] = React.useState<string>();
|
const [result, setResult] = React.useState<string>()
|
||||||
const [isModalOpen, setIsModalOpen] = React.useState<boolean>(false);
|
const [isModalOpen, setIsModalOpen] = React.useState<boolean>(false)
|
||||||
|
|
||||||
const handlePick = (emoji: EmojiType) => {
|
const handlePick = (emoji: EmojiType) => {
|
||||||
console.log(emoji);
|
console.log(emoji)
|
||||||
setResult(emoji.emoji);
|
setResult(emoji.emoji)
|
||||||
setIsModalOpen((prev) => !prev);
|
setIsModalOpen((prev) => !prev)
|
||||||
};
|
}
|
||||||
return (
|
return (
|
||||||
<SafeAreaView style={styles.container}>
|
<SafeAreaView style={styles.container}>
|
||||||
<Text style={styles.text}>Result: {result}</Text>
|
<Text style={styles.text}>Result: {result}</Text>
|
||||||
|
@ -28,8 +28,8 @@ const StaticModal = () => {
|
||||||
defaultHeight="65%"
|
defaultHeight="65%"
|
||||||
/>
|
/>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
|
@ -40,6 +40,6 @@ const styles = StyleSheet.create({
|
||||||
margin: 64,
|
margin: 64,
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
||||||
export default StaticModal;
|
export default StaticModal
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import { StyleSheet, Text, TouchableOpacity } from 'react-native';
|
import { StyleSheet, Text, TouchableOpacity } from 'react-native'
|
||||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
import { SafeAreaView } from 'react-native-safe-area-context'
|
||||||
import EmojiPicker from 'rn-emoji-keyboard';
|
import EmojiPicker from 'rn-emoji-keyboard'
|
||||||
import type { EmojiType } from 'src/types';
|
import type { EmojiType } from 'src/types'
|
||||||
|
|
||||||
const TopCategory = () => {
|
const TopCategory = () => {
|
||||||
const [result, setResult] = React.useState<string>();
|
const [result, setResult] = React.useState<string>()
|
||||||
const [isModalOpen, setIsModalOpen] = React.useState<boolean>(false);
|
const [isModalOpen, setIsModalOpen] = React.useState<boolean>(false)
|
||||||
|
|
||||||
const handlePick = (emoji: EmojiType) => {
|
const handlePick = (emoji: EmojiType) => {
|
||||||
setResult(emoji.emoji);
|
setResult(emoji.emoji)
|
||||||
setIsModalOpen((prev) => !prev);
|
setIsModalOpen((prev) => !prev)
|
||||||
};
|
}
|
||||||
return (
|
return (
|
||||||
<SafeAreaView style={styles.container}>
|
<SafeAreaView style={styles.container}>
|
||||||
<Text style={styles.text}>Result: {result}</Text>
|
<Text style={styles.text}>Result: {result}</Text>
|
||||||
|
@ -26,8 +26,8 @@ const TopCategory = () => {
|
||||||
categoryPosition="top"
|
categoryPosition="top"
|
||||||
/>
|
/>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
|
@ -38,6 +38,6 @@ const styles = StyleSheet.create({
|
||||||
margin: 64,
|
margin: 64,
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
||||||
export default TopCategory;
|
export default TopCategory
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import { StyleSheet, Text, TouchableOpacity } from 'react-native';
|
import { StyleSheet, Text, TouchableOpacity } from 'react-native'
|
||||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
import { SafeAreaView } from 'react-native-safe-area-context'
|
||||||
import EmojiPicker, { pl } from 'rn-emoji-keyboard';
|
import EmojiPicker, { pl } from 'rn-emoji-keyboard'
|
||||||
import type { EmojiType } from 'src/types';
|
import type { EmojiType } from 'src/types'
|
||||||
|
|
||||||
const Translated = () => {
|
const Translated = () => {
|
||||||
const [result, setResult] = React.useState<string>();
|
const [result, setResult] = React.useState<string>()
|
||||||
const [isModalOpen, setIsModalOpen] = React.useState<boolean>(false);
|
const [isModalOpen, setIsModalOpen] = React.useState<boolean>(false)
|
||||||
|
|
||||||
const handlePick = (emoji: EmojiType) => {
|
const handlePick = (emoji: EmojiType) => {
|
||||||
console.log(emoji);
|
console.log(emoji)
|
||||||
setResult(emoji.emoji);
|
setResult(emoji.emoji)
|
||||||
setIsModalOpen((prev) => !prev);
|
setIsModalOpen((prev) => !prev)
|
||||||
};
|
}
|
||||||
return (
|
return (
|
||||||
<SafeAreaView style={styles.container}>
|
<SafeAreaView style={styles.container}>
|
||||||
<Text style={styles.text}>Emotka: {result}</Text>
|
<Text style={styles.text}>Emotka: {result}</Text>
|
||||||
|
@ -27,8 +27,8 @@ const Translated = () => {
|
||||||
translation={pl}
|
translation={pl}
|
||||||
/>
|
/>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
|
@ -39,6 +39,6 @@ const styles = StyleSheet.create({
|
||||||
margin: 64,
|
margin: 64,
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
||||||
export default Translated;
|
export default Translated
|
||||||
|
|
21
package.json
21
package.json
|
@ -52,6 +52,7 @@
|
||||||
"@commitlint/config-conventional": "^11.0.0",
|
"@commitlint/config-conventional": "^11.0.0",
|
||||||
"@react-native-community/eslint-config": "^2.0.0",
|
"@react-native-community/eslint-config": "^2.0.0",
|
||||||
"@release-it/conventional-changelog": "^2.0.0",
|
"@release-it/conventional-changelog": "^2.0.0",
|
||||||
|
"@twgdev/prettier-config": "^1.0.2",
|
||||||
"@types/jest": "^26.0.0",
|
"@types/jest": "^26.0.0",
|
||||||
"@types/react": "^16.9.19",
|
"@types/react": "^16.9.19",
|
||||||
"@types/react-native": "0.62.13",
|
"@types/react-native": "0.62.13",
|
||||||
|
@ -116,31 +117,13 @@
|
||||||
"extends": [
|
"extends": [
|
||||||
"@react-native-community",
|
"@react-native-community",
|
||||||
"prettier"
|
"prettier"
|
||||||
],
|
|
||||||
"rules": {
|
|
||||||
"prettier/prettier": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
"quoteProps": "consistent",
|
|
||||||
"singleQuote": true,
|
|
||||||
"tabWidth": 2,
|
|
||||||
"trailingComma": "es5",
|
|
||||||
"useTabs": false
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"eslintIgnore": [
|
"eslintIgnore": [
|
||||||
"node_modules/",
|
"node_modules/",
|
||||||
"lib/"
|
"lib/"
|
||||||
],
|
],
|
||||||
"prettier": {
|
"prettier": "@twgdev/prettier-config",
|
||||||
"quoteProps": "consistent",
|
|
||||||
"singleQuote": true,
|
|
||||||
"tabWidth": 2,
|
|
||||||
"trailingComma": "es5",
|
|
||||||
"useTabs": false
|
|
||||||
},
|
|
||||||
"react-native-builder-bob": {
|
"react-native-builder-bob": {
|
||||||
"source": "src",
|
"source": "src",
|
||||||
"output": "lib",
|
"output": "lib",
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
const path = require('path');
|
const path = require('path')
|
||||||
const child_process = require('child_process');
|
const child_process = require('child_process')
|
||||||
|
|
||||||
const root = path.resolve(__dirname, '..');
|
const root = path.resolve(__dirname, '..')
|
||||||
const args = process.argv.slice(2);
|
const args = process.argv.slice(2)
|
||||||
const options = {
|
const options = {
|
||||||
cwd: process.cwd(),
|
cwd: process.cwd(),
|
||||||
env: process.env,
|
env: process.env,
|
||||||
stdio: 'inherit',
|
stdio: 'inherit',
|
||||||
encoding: 'utf-8',
|
encoding: 'utf-8',
|
||||||
};
|
}
|
||||||
|
|
||||||
let result;
|
let result
|
||||||
|
|
||||||
if (process.cwd() !== root || args.length) {
|
if (process.cwd() !== root || args.length) {
|
||||||
// We're not in the root of the project, or additional arguments were passed
|
// We're not in the root of the project, or additional arguments were passed
|
||||||
// In this case, forward the command to `yarn`
|
// In this case, forward the command to `yarn`
|
||||||
result = child_process.spawnSync('yarn', args, options);
|
result = child_process.spawnSync('yarn', args, options)
|
||||||
} else {
|
} else {
|
||||||
// If `yarn` is run without arguments, perform bootstrap
|
// If `yarn` is run without arguments, perform bootstrap
|
||||||
result = child_process.spawnSync('yarn', ['bootstrap'], options);
|
result = child_process.spawnSync('yarn', ['bootstrap'], options)
|
||||||
}
|
}
|
||||||
|
|
||||||
process.exitCode = result.status;
|
process.exitCode = result.status
|
||||||
|
|
|
@ -1,24 +1,20 @@
|
||||||
const json = require('unicode-emoji-json/data-by-group.json');
|
const json = require('unicode-emoji-json/data-by-group.json')
|
||||||
const fs = require('fs');
|
const fs = require('fs')
|
||||||
|
|
||||||
const newArray = [];
|
const newArray = []
|
||||||
for (const [key, value] of Object.entries(json)) {
|
for (const [key, value] of Object.entries(json)) {
|
||||||
const newData = value.map((emoji) => ({
|
const newData = value.map((emoji) => ({
|
||||||
emoji: emoji.emoji,
|
emoji: emoji.emoji,
|
||||||
name: emoji.name,
|
name: emoji.name,
|
||||||
v: emoji.unicode_version,
|
v: emoji.unicode_version,
|
||||||
}));
|
}))
|
||||||
newArray.push({
|
newArray.push({
|
||||||
title: key.replace(' & ', '_').replace(' ', '_').toLocaleLowerCase(),
|
title: key.replace(' & ', '_').replace(' ', '_').toLocaleLowerCase(),
|
||||||
data: newData,
|
data: newData,
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.writeFile(
|
fs.writeFile('./src/assets/emojis.json', JSON.stringify(newArray), function (err) {
|
||||||
'./src/assets/emojis.json',
|
if (err) return console.log(err)
|
||||||
JSON.stringify(newArray),
|
console.log('emojis.json successfully saved to assets folder')
|
||||||
function (err) {
|
})
|
||||||
if (err) return console.log(err);
|
|
||||||
console.log('emojis.json successfully saved to assets folder');
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
|
@ -1,19 +1,16 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import { EmojiStaticKeyboard } from './components/EmojiStaticKeyboard';
|
import { EmojiStaticKeyboard } from './components/EmojiStaticKeyboard'
|
||||||
import { KeyboardProvider } from './contexts/KeyboardProvider';
|
import { KeyboardProvider } from './contexts/KeyboardProvider'
|
||||||
import type {
|
import type { KeyboardProps, OnEmojiSelected } from './contexts/KeyboardContext'
|
||||||
KeyboardProps,
|
|
||||||
OnEmojiSelected,
|
|
||||||
} from './contexts/KeyboardContext';
|
|
||||||
|
|
||||||
type EmojiKeyboardProps = {
|
type EmojiKeyboardProps = {
|
||||||
onEmojiSelected: OnEmojiSelected;
|
onEmojiSelected: OnEmojiSelected
|
||||||
} & Partial<KeyboardProps>;
|
} & Partial<KeyboardProps>
|
||||||
|
|
||||||
export const EmojiKeyboard = (props: EmojiKeyboardProps) => {
|
export const EmojiKeyboard = (props: EmojiKeyboardProps) => {
|
||||||
return (
|
return (
|
||||||
<KeyboardProvider {...props}>
|
<KeyboardProvider {...props}>
|
||||||
<EmojiStaticKeyboard />
|
<EmojiStaticKeyboard />
|
||||||
</KeyboardProvider>
|
</KeyboardProvider>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import { Animated, useWindowDimensions } from 'react-native';
|
import { Animated, useWindowDimensions } from 'react-native'
|
||||||
import { EmojiStaticKeyboard } from './components/EmojiStaticKeyboard';
|
import { EmojiStaticKeyboard } from './components/EmojiStaticKeyboard'
|
||||||
import { Knob } from './components/Knob';
|
import { Knob } from './components/Knob'
|
||||||
import {
|
import { defaultKeyboardContext, KeyboardProvider } from './contexts/KeyboardProvider'
|
||||||
defaultKeyboardContext,
|
import type { KeyboardProps } from './contexts/KeyboardContext'
|
||||||
KeyboardProvider,
|
import type { EmojiType } from './types'
|
||||||
} from './contexts/KeyboardProvider';
|
import { ModalWithBackdrop } from './components/ModalWithBackdrop'
|
||||||
import type { KeyboardProps } from './contexts/KeyboardContext';
|
import { getHeight } from './utils'
|
||||||
import type { EmojiType } from './types';
|
|
||||||
import { ModalWithBackdrop } from './components/ModalWithBackdrop';
|
|
||||||
import { getHeight } from './utils';
|
|
||||||
|
|
||||||
export const EmojiPicker = ({
|
export const EmojiPicker = ({
|
||||||
onEmojiSelected,
|
onEmojiSelected,
|
||||||
|
@ -19,55 +16,49 @@ export const EmojiPicker = ({
|
||||||
defaultHeight = defaultKeyboardContext.defaultHeight,
|
defaultHeight = defaultKeyboardContext.defaultHeight,
|
||||||
...props
|
...props
|
||||||
}: KeyboardProps) => {
|
}: KeyboardProps) => {
|
||||||
const { height: screenHeight } = useWindowDimensions();
|
const { height: screenHeight } = useWindowDimensions()
|
||||||
const offsetY = React.useRef(new Animated.Value(0)).current;
|
const offsetY = React.useRef(new Animated.Value(0)).current
|
||||||
const height = React.useRef(
|
const height = React.useRef(new Animated.Value(getHeight(defaultHeight, screenHeight))).current
|
||||||
new Animated.Value(getHeight(defaultHeight, screenHeight))
|
const translateY = React.useRef(new Animated.Value(0)).current
|
||||||
).current;
|
|
||||||
const translateY = React.useRef(new Animated.Value(0)).current;
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
Animated.timing(translateY, {
|
Animated.timing(translateY, {
|
||||||
toValue: open ? 0 : screenHeight,
|
toValue: open ? 0 : screenHeight,
|
||||||
useNativeDriver: true,
|
useNativeDriver: true,
|
||||||
duration: 500,
|
duration: 500,
|
||||||
}).start();
|
}).start()
|
||||||
}, [open, screenHeight, translateY]);
|
}, [open, screenHeight, translateY])
|
||||||
|
|
||||||
const close = () => {
|
const close = () => {
|
||||||
height.setValue(getHeight(defaultHeight, screenHeight));
|
height.setValue(getHeight(defaultHeight, screenHeight))
|
||||||
offsetY.setValue(0);
|
offsetY.setValue(0)
|
||||||
onClose();
|
onClose()
|
||||||
};
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<KeyboardProvider
|
<KeyboardProvider
|
||||||
onEmojiSelected={(emoji: EmojiType) => {
|
onEmojiSelected={(emoji: EmojiType) => {
|
||||||
onEmojiSelected(emoji);
|
onEmojiSelected(emoji)
|
||||||
close();
|
close()
|
||||||
}}
|
}}
|
||||||
open={open}
|
open={open}
|
||||||
onClose={close}
|
onClose={close}
|
||||||
expandable={expandable}
|
expandable={expandable}
|
||||||
defaultHeight={defaultHeight}
|
defaultHeight={defaultHeight}
|
||||||
{...props}
|
{...props}>
|
||||||
>
|
|
||||||
<ModalWithBackdrop isOpen={open} backdropPress={close}>
|
<ModalWithBackdrop isOpen={open} backdropPress={close}>
|
||||||
<>
|
<>
|
||||||
{expandable && (
|
{expandable && <Knob height={height} offsetY={offsetY} onClose={onClose} />}
|
||||||
<Knob height={height} offsetY={offsetY} onClose={onClose} />
|
|
||||||
)}
|
|
||||||
<Animated.View
|
<Animated.View
|
||||||
style={[
|
style={[
|
||||||
{
|
{
|
||||||
height: Animated.subtract(height, offsetY),
|
height: Animated.subtract(height, offsetY),
|
||||||
},
|
},
|
||||||
]}
|
]}>
|
||||||
>
|
|
||||||
<EmojiStaticKeyboard />
|
<EmojiStaticKeyboard />
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
</>
|
</>
|
||||||
</ModalWithBackdrop>
|
</ModalWithBackdrop>
|
||||||
</KeyboardProvider>
|
</KeyboardProvider>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import Svg, { FillProps, Path } from 'react-native-svg';
|
import Svg, { FillProps, Path } from 'react-native-svg'
|
||||||
|
|
||||||
export default ({ fill }: FillProps) => (
|
export default ({ fill }: FillProps) => (
|
||||||
<Svg width="22" height="22" viewBox="0 0 22 22" fill="none">
|
<Svg width="22" height="22" viewBox="0 0 22 22" fill="none">
|
||||||
|
@ -8,4 +8,4 @@ export default ({ fill }: FillProps) => (
|
||||||
fill={fill}
|
fill={fill}
|
||||||
/>
|
/>
|
||||||
</Svg>
|
</Svg>
|
||||||
);
|
)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import Svg, { FillProps, Path } from 'react-native-svg';
|
import Svg, { FillProps, Path } from 'react-native-svg'
|
||||||
|
|
||||||
export default ({ fill }: FillProps) => (
|
export default ({ fill }: FillProps) => (
|
||||||
<Svg width="22" height="22" viewBox="0 0 22 22" fill="none">
|
<Svg width="22" height="22" viewBox="0 0 22 22" fill="none">
|
||||||
|
@ -8,4 +8,4 @@ export default ({ fill }: FillProps) => (
|
||||||
fill={fill}
|
fill={fill}
|
||||||
/>
|
/>
|
||||||
</Svg>
|
</Svg>
|
||||||
);
|
)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import Svg, { FillProps, Path } from 'react-native-svg';
|
import Svg, { FillProps, Path } from 'react-native-svg'
|
||||||
|
|
||||||
export default ({ fill }: FillProps) => (
|
export default ({ fill }: FillProps) => (
|
||||||
<Svg width="23" height="23" viewBox="0 0 24 24" fill="none">
|
<Svg width="23" height="23" viewBox="0 0 24 24" fill="none">
|
||||||
|
@ -8,4 +8,4 @@ export default ({ fill }: FillProps) => (
|
||||||
fill={fill}
|
fill={fill}
|
||||||
/>
|
/>
|
||||||
</Svg>
|
</Svg>
|
||||||
);
|
)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import Svg, { FillProps, Path } from 'react-native-svg';
|
import Svg, { FillProps, Path } from 'react-native-svg'
|
||||||
|
|
||||||
export default ({ fill }: FillProps) => (
|
export default ({ fill }: FillProps) => (
|
||||||
<Svg width="22" height="22" viewBox="0 0 22 22" fill="none">
|
<Svg width="22" height="22" viewBox="0 0 22 22" fill="none">
|
||||||
|
@ -10,4 +10,4 @@ export default ({ fill }: FillProps) => (
|
||||||
fill={fill}
|
fill={fill}
|
||||||
/>
|
/>
|
||||||
</Svg>
|
</Svg>
|
||||||
);
|
)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import Svg, { FillProps, Path } from 'react-native-svg';
|
import Svg, { FillProps, Path } from 'react-native-svg'
|
||||||
|
|
||||||
export default ({ fill }: FillProps) => (
|
export default ({ fill }: FillProps) => (
|
||||||
<Svg width="22" height="22" viewBox="0 0 22 22" fill="none">
|
<Svg width="22" height="22" viewBox="0 0 22 22" fill="none">
|
||||||
|
@ -8,4 +8,4 @@ export default ({ fill }: FillProps) => (
|
||||||
fill={fill}
|
fill={fill}
|
||||||
/>
|
/>
|
||||||
</Svg>
|
</Svg>
|
||||||
);
|
)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import Svg, { FillProps, Path } from 'react-native-svg';
|
import Svg, { FillProps, Path } from 'react-native-svg'
|
||||||
|
|
||||||
export default ({ fill }: FillProps) => (
|
export default ({ fill }: FillProps) => (
|
||||||
<Svg width="22" height="22" viewBox="0 0 22 22" fill="none">
|
<Svg width="22" height="22" viewBox="0 0 22 22" fill="none">
|
||||||
|
@ -8,4 +8,4 @@ export default ({ fill }: FillProps) => (
|
||||||
fill={fill}
|
fill={fill}
|
||||||
/>
|
/>
|
||||||
</Svg>
|
</Svg>
|
||||||
);
|
)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import Svg, { FillProps, Path } from 'react-native-svg';
|
import Svg, { FillProps, Path } from 'react-native-svg'
|
||||||
|
|
||||||
export default ({ fill }: FillProps) => (
|
export default ({ fill }: FillProps) => (
|
||||||
<Svg width="22" height="22" viewBox="0 0 22 22" fill="none">
|
<Svg width="22" height="22" viewBox="0 0 22 22" fill="none">
|
||||||
|
@ -8,4 +8,4 @@ export default ({ fill }: FillProps) => (
|
||||||
fill={fill}
|
fill={fill}
|
||||||
/>
|
/>
|
||||||
</Svg>
|
</Svg>
|
||||||
);
|
)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import Svg, { FillProps, Path } from 'react-native-svg';
|
import Svg, { FillProps, Path } from 'react-native-svg'
|
||||||
|
|
||||||
export default ({ fill }: FillProps) => (
|
export default ({ fill }: FillProps) => (
|
||||||
<Svg width="22" height="22" viewBox="0 0 22 22" fill="none">
|
<Svg width="22" height="22" viewBox="0 0 22 22" fill="none">
|
||||||
|
@ -8,4 +8,4 @@ export default ({ fill }: FillProps) => (
|
||||||
fill={fill}
|
fill={fill}
|
||||||
/>
|
/>
|
||||||
</Svg>
|
</Svg>
|
||||||
);
|
)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import Svg, { FillProps, Path } from 'react-native-svg';
|
import Svg, { FillProps, Path } from 'react-native-svg'
|
||||||
|
|
||||||
export default ({ fill }: FillProps) => (
|
export default ({ fill }: FillProps) => (
|
||||||
<Svg width="23" height="23" viewBox="0 0 24 24" fill="none">
|
<Svg width="23" height="23" viewBox="0 0 24 24" fill="none">
|
||||||
|
@ -8,4 +8,4 @@ export default ({ fill }: FillProps) => (
|
||||||
fill={fill}
|
fill={fill}
|
||||||
/>
|
/>
|
||||||
</Svg>
|
</Svg>
|
||||||
);
|
)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import Svg, { FillProps, Path } from 'react-native-svg';
|
import Svg, { FillProps, Path } from 'react-native-svg'
|
||||||
|
|
||||||
export default ({ fill }: FillProps) => (
|
export default ({ fill }: FillProps) => (
|
||||||
<Svg width="22" height="22" viewBox="0 0 22 22" fill="none">
|
<Svg width="22" height="22" viewBox="0 0 22 22" fill="none">
|
||||||
|
@ -8,4 +8,4 @@ export default ({ fill }: FillProps) => (
|
||||||
fill={fill}
|
fill={fill}
|
||||||
/>
|
/>
|
||||||
</Svg>
|
</Svg>
|
||||||
);
|
)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import Svg, { FillProps, Path } from 'react-native-svg';
|
import Svg, { FillProps, Path } from 'react-native-svg'
|
||||||
|
|
||||||
export default ({ fill }: FillProps) => (
|
export default ({ fill }: FillProps) => (
|
||||||
<Svg width="22" height="22" viewBox="0 0 22 22" fill="none">
|
<Svg width="22" height="22" viewBox="0 0 22 22" fill="none">
|
||||||
|
@ -8,4 +8,4 @@ export default ({ fill }: FillProps) => (
|
||||||
fill={fill}
|
fill={fill}
|
||||||
/>
|
/>
|
||||||
</Svg>
|
</Svg>
|
||||||
);
|
)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import Svg, { FillProps, Path } from 'react-native-svg';
|
import Svg, { FillProps, Path } from 'react-native-svg'
|
||||||
|
|
||||||
export default ({ fill }: FillProps) => (
|
export default ({ fill }: FillProps) => (
|
||||||
<Svg width="22" height="22" viewBox="0 0 22 22" fill="none">
|
<Svg width="22" height="22" viewBox="0 0 22 22" fill="none">
|
||||||
|
@ -8,4 +8,4 @@ export default ({ fill }: FillProps) => (
|
||||||
fill={fill}
|
fill={fill}
|
||||||
/>
|
/>
|
||||||
</Svg>
|
</Svg>
|
||||||
);
|
)
|
||||||
|
|
|
@ -1,20 +1,16 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import { Animated, FlatList, StyleSheet, View, ViewStyle } from 'react-native';
|
import { Animated, FlatList, StyleSheet, View, ViewStyle } from 'react-native'
|
||||||
import { useKeyboardStore } from '../store/useKeyboardStore';
|
import { useKeyboardStore } from '../store/useKeyboardStore'
|
||||||
import { defaultKeyboardContext } from '../contexts/KeyboardProvider';
|
import { defaultKeyboardContext } from '../contexts/KeyboardProvider'
|
||||||
import { KeyboardContext } from '../contexts/KeyboardContext';
|
import { KeyboardContext } from '../contexts/KeyboardContext'
|
||||||
import {
|
import { CATEGORIES_NAVIGATION, CategoryNavigationItem, CategoryTypes } from '../types'
|
||||||
CATEGORIES_NAVIGATION,
|
import { CategoryItem } from './CategoryItem'
|
||||||
CategoryNavigationItem,
|
import { exhaustiveTypeCheck, getCategoryIndex } from '../utils'
|
||||||
CategoryTypes,
|
|
||||||
} from '../types';
|
|
||||||
import { CategoryItem } from './CategoryItem';
|
|
||||||
import { exhaustiveTypeCheck, getCategoryIndex } from '../utils';
|
|
||||||
|
|
||||||
type CategoriesProps = {
|
type CategoriesProps = {
|
||||||
flatListRef: React.RefObject<FlatList>;
|
flatListRef: React.RefObject<FlatList>
|
||||||
scrollNav: Animated.Value;
|
scrollNav: Animated.Value
|
||||||
};
|
}
|
||||||
|
|
||||||
export const Categories = ({ flatListRef, scrollNav }: CategoriesProps) => {
|
export const Categories = ({ flatListRef, scrollNav }: CategoriesProps) => {
|
||||||
const {
|
const {
|
||||||
|
@ -26,27 +22,21 @@ export const Categories = ({ flatListRef, scrollNav }: CategoriesProps) => {
|
||||||
enableRecentlyUsed,
|
enableRecentlyUsed,
|
||||||
categoryPosition,
|
categoryPosition,
|
||||||
searchPhrase,
|
searchPhrase,
|
||||||
} = React.useContext(KeyboardContext);
|
} = React.useContext(KeyboardContext)
|
||||||
const { keyboardState } = useKeyboardStore();
|
const { keyboardState } = useKeyboardStore()
|
||||||
const handleScrollToCategory = React.useCallback(
|
const handleScrollToCategory = React.useCallback(
|
||||||
(category: CategoryTypes) => {
|
(category: CategoryTypes) => {
|
||||||
flatListRef?.current?.scrollToIndex(
|
flatListRef?.current?.scrollToIndex(getCategoryIndex(disabledCategory, category))
|
||||||
getCategoryIndex(disabledCategory, category)
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
[disabledCategory, flatListRef]
|
[disabledCategory, flatListRef]
|
||||||
);
|
)
|
||||||
|
|
||||||
const renderItem = React.useCallback(
|
const renderItem = React.useCallback(
|
||||||
({ item, index }: { item: CategoryNavigationItem; index: number }) => (
|
({ item, index }: { item: CategoryNavigationItem; index: number }) => (
|
||||||
<CategoryItem
|
<CategoryItem item={item} index={index} handleScrollToCategory={handleScrollToCategory} />
|
||||||
item={item}
|
|
||||||
index={index}
|
|
||||||
handleScrollToCategory={handleScrollToCategory}
|
|
||||||
/>
|
|
||||||
),
|
),
|
||||||
[handleScrollToCategory]
|
[handleScrollToCategory]
|
||||||
);
|
)
|
||||||
|
|
||||||
const activeIndicator = React.useCallback(
|
const activeIndicator = React.useCallback(
|
||||||
() => (
|
() => (
|
||||||
|
@ -63,51 +53,45 @@ export const Categories = ({ flatListRef, scrollNav }: CategoriesProps) => {
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
[activeCategoryContainerColor, scrollNav]
|
[activeCategoryContainerColor, scrollNav]
|
||||||
);
|
)
|
||||||
|
|
||||||
const getStylesBasedOnPosition = () => {
|
const getStylesBasedOnPosition = () => {
|
||||||
const style: ViewStyle[] = [styles.navigation];
|
const style: ViewStyle[] = [styles.navigation]
|
||||||
switch (categoryPosition) {
|
switch (categoryPosition) {
|
||||||
case 'floating':
|
case 'floating':
|
||||||
style.push(styles.navigationFloating);
|
style.push(styles.navigationFloating)
|
||||||
break;
|
break
|
||||||
case 'top':
|
case 'top':
|
||||||
style.push(styles.navigationTop);
|
style.push(styles.navigationTop)
|
||||||
break;
|
break
|
||||||
case 'bottom':
|
case 'bottom':
|
||||||
style.push(styles.navigationBottom);
|
style.push(styles.navigationBottom)
|
||||||
break;
|
break
|
||||||
default:
|
default:
|
||||||
exhaustiveTypeCheck(categoryPosition);
|
exhaustiveTypeCheck(categoryPosition)
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
categoryContainerColor !==
|
categoryContainerColor !== defaultKeyboardContext.categoryContainerColor ||
|
||||||
defaultKeyboardContext.categoryContainerColor ||
|
|
||||||
categoryPosition === 'floating'
|
categoryPosition === 'floating'
|
||||||
)
|
)
|
||||||
style.push({
|
style.push({
|
||||||
backgroundColor: categoryContainerColor,
|
backgroundColor: categoryContainerColor,
|
||||||
});
|
})
|
||||||
return style;
|
return style
|
||||||
};
|
}
|
||||||
|
|
||||||
const renderData = React.useMemo(() => {
|
const renderData = React.useMemo(() => {
|
||||||
const isRecentlyUsedHidden = (category: CategoryTypes) =>
|
const isRecentlyUsedHidden = (category: CategoryTypes) =>
|
||||||
category === 'recently_used' &&
|
category === 'recently_used' &&
|
||||||
(keyboardState.recentlyUsed.length === 0 || !enableRecentlyUsed);
|
(keyboardState.recentlyUsed.length === 0 || !enableRecentlyUsed)
|
||||||
return CATEGORIES_NAVIGATION.filter(({ category }) => {
|
return CATEGORIES_NAVIGATION.filter(({ category }) => {
|
||||||
if (searchPhrase === '' && category === 'search') return false;
|
if (searchPhrase === '' && category === 'search') return false
|
||||||
if (isRecentlyUsedHidden(category)) return false;
|
if (isRecentlyUsedHidden(category)) return false
|
||||||
return !disabledCategory.includes(category);
|
return !disabledCategory.includes(category)
|
||||||
});
|
})
|
||||||
}, [
|
}, [disabledCategory, enableRecentlyUsed, keyboardState.recentlyUsed.length, searchPhrase])
|
||||||
disabledCategory,
|
|
||||||
enableRecentlyUsed,
|
|
||||||
keyboardState.recentlyUsed.length,
|
|
||||||
searchPhrase,
|
|
||||||
]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={[categoryPosition === 'floating' && styles.floating]}>
|
<View style={[categoryPosition === 'floating' && styles.floating]}>
|
||||||
|
@ -126,8 +110,8 @@ export const Categories = ({ flatListRef, scrollNav }: CategoriesProps) => {
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
floating: {
|
floating: {
|
||||||
|
@ -175,4 +159,4 @@ const styles = StyleSheet.create({
|
||||||
width: 28,
|
width: 28,
|
||||||
height: 28,
|
height: 28,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
|
@ -1,31 +1,23 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import { View, StyleSheet, TouchableOpacity } from 'react-native';
|
import { View, StyleSheet, TouchableOpacity } from 'react-native'
|
||||||
import { KeyboardContext } from '../contexts/KeyboardContext';
|
import { KeyboardContext } from '../contexts/KeyboardContext'
|
||||||
import type { CategoryNavigationItem, CategoryTypes } from '../types';
|
import type { CategoryNavigationItem, CategoryTypes } from '../types'
|
||||||
import { Icon } from './Icon';
|
import { Icon } from './Icon'
|
||||||
|
|
||||||
type CategoryItemProps = {
|
type CategoryItemProps = {
|
||||||
item: CategoryNavigationItem;
|
item: CategoryNavigationItem
|
||||||
index: number;
|
index: number
|
||||||
handleScrollToCategory: (category: CategoryTypes) => void;
|
handleScrollToCategory: (category: CategoryTypes) => void
|
||||||
};
|
}
|
||||||
|
|
||||||
export const CategoryItem = ({
|
export const CategoryItem = ({ item, index, handleScrollToCategory }: CategoryItemProps) => {
|
||||||
item,
|
const { activeCategoryIndex, categoryColor, activeCategoryColor, setActiveCategoryIndex } =
|
||||||
index,
|
React.useContext(KeyboardContext)
|
||||||
handleScrollToCategory,
|
|
||||||
}: CategoryItemProps) => {
|
|
||||||
const {
|
|
||||||
activeCategoryIndex,
|
|
||||||
categoryColor,
|
|
||||||
activeCategoryColor,
|
|
||||||
setActiveCategoryIndex,
|
|
||||||
} = React.useContext(KeyboardContext);
|
|
||||||
|
|
||||||
const handleSelect = () => {
|
const handleSelect = () => {
|
||||||
handleScrollToCategory(item.category);
|
handleScrollToCategory(item.category)
|
||||||
setActiveCategoryIndex(index);
|
setActiveCategoryIndex(index)
|
||||||
};
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity onPress={handleSelect}>
|
<TouchableOpacity onPress={handleSelect}>
|
||||||
|
@ -38,8 +30,8 @@ export const CategoryItem = ({
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
|
@ -51,4 +43,4 @@ const styles = StyleSheet.create({
|
||||||
borderRadius: 6,
|
borderRadius: 6,
|
||||||
},
|
},
|
||||||
icon: { textAlign: 'center' },
|
icon: { textAlign: 'center' },
|
||||||
});
|
})
|
||||||
|
|
|
@ -1,24 +1,20 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
|
|
||||||
import { StyleSheet, View, Text, FlatList } from 'react-native';
|
import { StyleSheet, View, Text, FlatList } from 'react-native'
|
||||||
import type { EmojisByCategory, EmojiType, JsonEmoji } from '../types';
|
import type { EmojisByCategory, EmojiType, JsonEmoji } from '../types'
|
||||||
import { SingleEmoji } from './SingleEmoji';
|
import { SingleEmoji } from './SingleEmoji'
|
||||||
import { KeyboardContext } from '../contexts/KeyboardContext';
|
import { KeyboardContext } from '../contexts/KeyboardContext'
|
||||||
import { useKeyboardStore } from '../store/useKeyboardStore';
|
import { useKeyboardStore } from '../store/useKeyboardStore'
|
||||||
import { parseEmoji } from '../utils';
|
import { parseEmoji } from '../utils'
|
||||||
|
|
||||||
const emptyEmoji = {
|
const emptyEmoji = {
|
||||||
emoji: '',
|
emoji: '',
|
||||||
name: 'blank emoji',
|
name: 'blank emoji',
|
||||||
slug: 'blank_emoji',
|
slug: 'blank_emoji',
|
||||||
unicode_version: '0',
|
unicode_version: '0',
|
||||||
};
|
}
|
||||||
|
|
||||||
export const EmojiCategory = ({
|
export const EmojiCategory = ({ item: { title, data } }: { item: EmojisByCategory }) => {
|
||||||
item: { title, data },
|
|
||||||
}: {
|
|
||||||
item: EmojisByCategory;
|
|
||||||
}) => {
|
|
||||||
const {
|
const {
|
||||||
onEmojiSelected,
|
onEmojiSelected,
|
||||||
emojiSize,
|
emojiSize,
|
||||||
|
@ -28,55 +24,47 @@ export const EmojiCategory = ({
|
||||||
headerStyles,
|
headerStyles,
|
||||||
translation,
|
translation,
|
||||||
categoryPosition,
|
categoryPosition,
|
||||||
} = React.useContext(KeyboardContext);
|
} = React.useContext(KeyboardContext)
|
||||||
|
|
||||||
const { setKeyboardState } = useKeyboardStore();
|
const { setKeyboardState } = useKeyboardStore()
|
||||||
|
|
||||||
const [empty, setEmpty] = React.useState<EmojiType[]>([]);
|
const [empty, setEmpty] = React.useState<EmojiType[]>([])
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (data.length % numberOfColumns) {
|
if (data.length % numberOfColumns) {
|
||||||
const fillWithEmpty = new Array(
|
const fillWithEmpty = new Array(numberOfColumns - (data.length % numberOfColumns)).fill(
|
||||||
numberOfColumns - (data.length % numberOfColumns)
|
emptyEmoji
|
||||||
).fill(emptyEmoji);
|
)
|
||||||
setEmpty(fillWithEmpty);
|
setEmpty(fillWithEmpty)
|
||||||
}
|
}
|
||||||
}, [numberOfColumns, data]);
|
}, [numberOfColumns, data])
|
||||||
|
|
||||||
const getItemLayout = (_: EmojiType[] | null | undefined, index: number) => ({
|
const getItemLayout = (_: EmojiType[] | null | undefined, index: number) => ({
|
||||||
length: emojiSize ? emojiSize : 0,
|
length: emojiSize ? emojiSize : 0,
|
||||||
offset: emojiSize * Math.ceil(index / numberOfColumns),
|
offset: emojiSize * Math.ceil(index / numberOfColumns),
|
||||||
index,
|
index,
|
||||||
});
|
})
|
||||||
|
|
||||||
const handleEmojiPress = React.useCallback(
|
const handleEmojiPress = React.useCallback(
|
||||||
(emoji: JsonEmoji) => {
|
(emoji: JsonEmoji) => {
|
||||||
if (emoji.name === 'blank emoji') return;
|
if (emoji.name === 'blank emoji') return
|
||||||
const parsedEmoji = parseEmoji(emoji);
|
const parsedEmoji = parseEmoji(emoji)
|
||||||
onEmojiSelected(parsedEmoji);
|
onEmojiSelected(parsedEmoji)
|
||||||
setKeyboardState({ type: 'RECENT_EMOJI_ADD', payload: emoji });
|
setKeyboardState({ type: 'RECENT_EMOJI_ADD', payload: emoji })
|
||||||
},
|
},
|
||||||
[onEmojiSelected, setKeyboardState]
|
[onEmojiSelected, setKeyboardState]
|
||||||
);
|
)
|
||||||
|
|
||||||
const renderItem = React.useCallback(
|
const renderItem = React.useCallback(
|
||||||
(props) => (
|
(props) => (
|
||||||
<SingleEmoji
|
<SingleEmoji {...props} onPress={() => handleEmojiPress(props.item)} emojiSize={emojiSize} />
|
||||||
{...props}
|
|
||||||
onPress={() => handleEmojiPress(props.item)}
|
|
||||||
emojiSize={emojiSize}
|
|
||||||
/>
|
|
||||||
),
|
),
|
||||||
[emojiSize, handleEmojiPress]
|
[emojiSize, handleEmojiPress]
|
||||||
);
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={[styles.container, { width: width }]}>
|
<View style={[styles.container, { width: width }]}>
|
||||||
{!hideHeader && (
|
{!hideHeader && <Text style={[styles.sectionTitle, headerStyles]}>{translation[title]}</Text>}
|
||||||
<Text style={[styles.sectionTitle, headerStyles]}>
|
|
||||||
{translation[title]}
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
<FlatList
|
<FlatList
|
||||||
data={[...data, ...empty]}
|
data={[...data, ...empty]}
|
||||||
keyExtractor={(emoji) => emoji.name}
|
keyExtractor={(emoji) => emoji.name}
|
||||||
|
@ -85,19 +73,13 @@ export const EmojiCategory = ({
|
||||||
removeClippedSubviews={true}
|
removeClippedSubviews={true}
|
||||||
getItemLayout={getItemLayout}
|
getItemLayout={getItemLayout}
|
||||||
ListFooterComponent={() => (
|
ListFooterComponent={() => (
|
||||||
<View
|
<View style={categoryPosition === 'floating' ? styles.footerFloating : styles.footer} />
|
||||||
style={
|
|
||||||
categoryPosition === 'floating'
|
|
||||||
? styles.footerFloating
|
|
||||||
: styles.footer
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
windowSize={20}
|
windowSize={20}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
|
@ -113,4 +95,4 @@ const styles = StyleSheet.create({
|
||||||
},
|
},
|
||||||
footer: { height: 8 },
|
footer: { height: 8 },
|
||||||
footerFloating: { height: 70 },
|
footerFloating: { height: 70 },
|
||||||
});
|
})
|
||||||
|
|
|
@ -1,24 +1,18 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
|
|
||||||
import {
|
import { StyleSheet, View, FlatList, useWindowDimensions, Animated } from 'react-native'
|
||||||
StyleSheet,
|
import type { CategoryTypes, EmojisByCategory } from '../types'
|
||||||
View,
|
import { EmojiCategory } from './EmojiCategory'
|
||||||
FlatList,
|
import { KeyboardContext } from '../contexts/KeyboardContext'
|
||||||
useWindowDimensions,
|
import { Categories } from './Categories'
|
||||||
Animated,
|
import emojisByGroup from '../assets/emojis.json'
|
||||||
} from 'react-native';
|
import { SearchBar } from './SearchBar'
|
||||||
import type { CategoryTypes, EmojisByCategory } from '../types';
|
import { useKeyboardStore } from '../store/useKeyboardStore'
|
||||||
import { EmojiCategory } from './EmojiCategory';
|
|
||||||
import { KeyboardContext } from '../contexts/KeyboardContext';
|
|
||||||
import { Categories } from './Categories';
|
|
||||||
import emojisByGroup from '../assets/emojis.json';
|
|
||||||
import { SearchBar } from './SearchBar';
|
|
||||||
import { useKeyboardStore } from '../store/useKeyboardStore';
|
|
||||||
|
|
||||||
const CATEGORY_ELEMENT_WIDTH = 37;
|
const CATEGORY_ELEMENT_WIDTH = 37
|
||||||
|
|
||||||
export const EmojiStaticKeyboard = () => {
|
export const EmojiStaticKeyboard = () => {
|
||||||
const { width } = useWindowDimensions();
|
const { width } = useWindowDimensions()
|
||||||
const {
|
const {
|
||||||
activeCategoryIndex,
|
activeCategoryIndex,
|
||||||
containerStyles,
|
containerStyles,
|
||||||
|
@ -29,41 +23,35 @@ export const EmojiStaticKeyboard = () => {
|
||||||
searchPhrase,
|
searchPhrase,
|
||||||
setActiveCategoryIndex,
|
setActiveCategoryIndex,
|
||||||
enableRecentlyUsed,
|
enableRecentlyUsed,
|
||||||
} = React.useContext(KeyboardContext);
|
} = React.useContext(KeyboardContext)
|
||||||
const { keyboardState } = useKeyboardStore();
|
const { keyboardState } = useKeyboardStore()
|
||||||
const flatListRef = React.useRef<FlatList>(null);
|
const flatListRef = React.useRef<FlatList>(null)
|
||||||
const scrollNav = React.useRef(new Animated.Value(0)).current;
|
const scrollNav = React.useRef(new Animated.Value(0)).current
|
||||||
|
|
||||||
const getItemLayout = (
|
const getItemLayout = (_: CategoryTypes[] | null | undefined, index: number) => ({
|
||||||
_: CategoryTypes[] | null | undefined,
|
|
||||||
index: number
|
|
||||||
) => ({
|
|
||||||
length: width,
|
length: width,
|
||||||
offset: width * index,
|
offset: width * index,
|
||||||
index,
|
index,
|
||||||
});
|
})
|
||||||
|
|
||||||
const renderItem = React.useCallback(
|
const renderItem = React.useCallback((props) => <EmojiCategory {...props} />, [])
|
||||||
(props) => <EmojiCategory {...props} />,
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
Animated.spring(scrollNav, {
|
Animated.spring(scrollNav, {
|
||||||
toValue: activeCategoryIndex * CATEGORY_ELEMENT_WIDTH,
|
toValue: activeCategoryIndex * CATEGORY_ELEMENT_WIDTH,
|
||||||
useNativeDriver: true,
|
useNativeDriver: true,
|
||||||
}).start();
|
}).start()
|
||||||
}, [activeCategoryIndex, scrollNav]);
|
}, [activeCategoryIndex, scrollNav])
|
||||||
|
|
||||||
const renderList = React.useMemo(() => {
|
const renderList = React.useMemo(() => {
|
||||||
const data = emojisByGroup.filter((category) => {
|
const data = emojisByGroup.filter((category) => {
|
||||||
const title = category.title as CategoryTypes;
|
const title = category.title as CategoryTypes
|
||||||
return !disabledCategory.includes(title);
|
return !disabledCategory.includes(title)
|
||||||
});
|
})
|
||||||
if (keyboardState.recentlyUsed.length && enableRecentlyUsed) {
|
if (keyboardState.recentlyUsed.length && enableRecentlyUsed) {
|
||||||
data.push({
|
data.push({
|
||||||
title: 'recently_used',
|
title: 'recently_used',
|
||||||
data: keyboardState.recentlyUsed,
|
data: keyboardState.recentlyUsed,
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
data.push({
|
data.push({
|
||||||
title: 'search',
|
title: 'search',
|
||||||
|
@ -71,24 +59,19 @@ export const EmojiStaticKeyboard = () => {
|
||||||
.map((group) => group.data)
|
.map((group) => group.data)
|
||||||
.flat()
|
.flat()
|
||||||
.filter((emoji) => {
|
.filter((emoji) => {
|
||||||
if (searchPhrase && searchPhrase.length < 2) return false;
|
if (searchPhrase && searchPhrase.length < 2) return false
|
||||||
return emoji.name.toLowerCase().includes(searchPhrase.toLowerCase());
|
return emoji.name.toLowerCase().includes(searchPhrase.toLowerCase())
|
||||||
}),
|
}),
|
||||||
});
|
})
|
||||||
return data;
|
return data
|
||||||
}, [
|
}, [disabledCategory, enableRecentlyUsed, keyboardState.recentlyUsed, searchPhrase])
|
||||||
disabledCategory,
|
|
||||||
enableRecentlyUsed,
|
|
||||||
keyboardState.recentlyUsed,
|
|
||||||
searchPhrase,
|
|
||||||
]);
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (searchPhrase !== '') {
|
if (searchPhrase !== '') {
|
||||||
flatListRef.current?.scrollToEnd();
|
flatListRef.current?.scrollToEnd()
|
||||||
setActiveCategoryIndex(renderList.length - 1);
|
setActiveCategoryIndex(renderList.length - 1)
|
||||||
}
|
}
|
||||||
}, [renderList, searchPhrase, setActiveCategoryIndex]);
|
}, [renderList, searchPhrase, setActiveCategoryIndex])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
|
@ -97,8 +80,7 @@ export const EmojiStaticKeyboard = () => {
|
||||||
styles.containerShadow,
|
styles.containerShadow,
|
||||||
categoryPosition === 'top' && styles.containerReverse,
|
categoryPosition === 'top' && styles.containerReverse,
|
||||||
containerStyles,
|
containerStyles,
|
||||||
]}
|
]}>
|
||||||
>
|
|
||||||
{enableSearchBar && <SearchBar flatListRef={flatListRef} />}
|
{enableSearchBar && <SearchBar flatListRef={flatListRef} />}
|
||||||
<Animated.FlatList
|
<Animated.FlatList
|
||||||
extraData={[keyboardState.recentlyUsed.length, searchPhrase]}
|
extraData={[keyboardState.recentlyUsed.length, searchPhrase]}
|
||||||
|
@ -120,8 +102,8 @@ export const EmojiStaticKeyboard = () => {
|
||||||
/>
|
/>
|
||||||
<Categories flatListRef={flatListRef} scrollNav={scrollNav} />
|
<Categories flatListRef={flatListRef} scrollNav={scrollNav} />
|
||||||
</View>
|
</View>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
|
@ -137,4 +119,4 @@ const styles = StyleSheet.create({
|
||||||
shadowRadius: 5,
|
shadowRadius: 5,
|
||||||
elevation: 10,
|
elevation: 10,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import Flag from '../assets/Flag';
|
import Flag from '../assets/Flag'
|
||||||
import Football from '../assets/Football';
|
import Football from '../assets/Football'
|
||||||
import Lightbulb from '../assets/Lightbulb';
|
import Lightbulb from '../assets/Lightbulb'
|
||||||
import Pizza from '../assets/Pizza';
|
import Pizza from '../assets/Pizza'
|
||||||
import Plane from '../assets/Plane';
|
import Plane from '../assets/Plane'
|
||||||
import Smile from '../assets/Smile';
|
import Smile from '../assets/Smile'
|
||||||
import Trees from '../assets/Trees';
|
import Trees from '../assets/Trees'
|
||||||
import Ban from '../assets/Ban';
|
import Ban from '../assets/Ban'
|
||||||
import Users from '../assets/Users';
|
import Users from '../assets/Users'
|
||||||
import Search from '../assets/Search';
|
import Search from '../assets/Search'
|
||||||
import Close from '../assets/Close';
|
import Close from '../assets/Close'
|
||||||
import Clock from '../assets/Clock';
|
import Clock from '../assets/Clock'
|
||||||
import type { IconNames } from '../types';
|
import type { IconNames } from '../types'
|
||||||
import { exhaustiveTypeCheck } from '../utils';
|
import { exhaustiveTypeCheck } from '../utils'
|
||||||
|
|
||||||
export const Icon = ({
|
export const Icon = ({
|
||||||
iconName,
|
iconName,
|
||||||
|
@ -20,39 +20,39 @@ export const Icon = ({
|
||||||
normalColor,
|
normalColor,
|
||||||
activeColor,
|
activeColor,
|
||||||
}: {
|
}: {
|
||||||
iconName: IconNames | 'Close';
|
iconName: IconNames | 'Close'
|
||||||
isActive: boolean;
|
isActive: boolean
|
||||||
normalColor: string;
|
normalColor: string
|
||||||
activeColor: string;
|
activeColor: string
|
||||||
}) => {
|
}) => {
|
||||||
const color = isActive ? activeColor : normalColor;
|
const color = isActive ? activeColor : normalColor
|
||||||
switch (iconName) {
|
switch (iconName) {
|
||||||
case 'Smile':
|
case 'Smile':
|
||||||
return <Smile fill={color} />;
|
return <Smile fill={color} />
|
||||||
case 'Trees':
|
case 'Trees':
|
||||||
return <Trees fill={color} />;
|
return <Trees fill={color} />
|
||||||
case 'Pizza':
|
case 'Pizza':
|
||||||
return <Pizza fill={color} />;
|
return <Pizza fill={color} />
|
||||||
case 'Plane':
|
case 'Plane':
|
||||||
return <Plane fill={color} />;
|
return <Plane fill={color} />
|
||||||
case 'Football':
|
case 'Football':
|
||||||
return <Football fill={color} />;
|
return <Football fill={color} />
|
||||||
case 'Lightbulb':
|
case 'Lightbulb':
|
||||||
return <Lightbulb fill={color} />;
|
return <Lightbulb fill={color} />
|
||||||
case 'Flag':
|
case 'Flag':
|
||||||
return <Flag fill={color} />;
|
return <Flag fill={color} />
|
||||||
case 'Ban':
|
case 'Ban':
|
||||||
return <Ban fill={color} />;
|
return <Ban fill={color} />
|
||||||
case 'Users':
|
case 'Users':
|
||||||
return <Users fill={color} />;
|
return <Users fill={color} />
|
||||||
case 'Search':
|
case 'Search':
|
||||||
return <Search fill={color} />;
|
return <Search fill={color} />
|
||||||
case 'Close':
|
case 'Close':
|
||||||
return <Close fill={color} />;
|
return <Close fill={color} />
|
||||||
case 'Clock':
|
case 'Clock':
|
||||||
return <Clock fill={color} />;
|
return <Clock fill={color} />
|
||||||
default:
|
default:
|
||||||
exhaustiveTypeCheck(iconName);
|
exhaustiveTypeCheck(iconName)
|
||||||
return null;
|
return null
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,24 +1,17 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import {
|
import { Animated, useWindowDimensions, StyleSheet, View, PanResponder } from 'react-native'
|
||||||
Animated,
|
import { getHeight } from '../utils'
|
||||||
useWindowDimensions,
|
import { KeyboardContext } from '../contexts/KeyboardContext'
|
||||||
StyleSheet,
|
|
||||||
View,
|
|
||||||
PanResponder,
|
|
||||||
} from 'react-native';
|
|
||||||
import { getHeight } from '../utils';
|
|
||||||
import { KeyboardContext } from '../contexts/KeyboardContext';
|
|
||||||
|
|
||||||
type KnobProps = {
|
type KnobProps = {
|
||||||
offsetY: Animated.Value;
|
offsetY: Animated.Value
|
||||||
height: Animated.Value;
|
height: Animated.Value
|
||||||
onClose: () => void;
|
onClose: () => void
|
||||||
};
|
}
|
||||||
|
|
||||||
export const Knob = ({ offsetY, height, onClose }: KnobProps) => {
|
export const Knob = ({ offsetY, height, onClose }: KnobProps) => {
|
||||||
const { height: screenHeight } = useWindowDimensions();
|
const { height: screenHeight } = useWindowDimensions()
|
||||||
const { expandedHeight, defaultHeight, knobStyles } =
|
const { expandedHeight, defaultHeight, knobStyles } = React.useContext(KeyboardContext)
|
||||||
React.useContext(KeyboardContext);
|
|
||||||
|
|
||||||
const panResponder = React.useRef(
|
const panResponder = React.useRef(
|
||||||
PanResponder.create({
|
PanResponder.create({
|
||||||
|
@ -34,28 +27,28 @@ export const Knob = ({ offsetY, height, onClose }: KnobProps) => {
|
||||||
Animated.spring(offsetY, {
|
Animated.spring(offsetY, {
|
||||||
useNativeDriver: false,
|
useNativeDriver: false,
|
||||||
toValue: 0,
|
toValue: 0,
|
||||||
}).start();
|
}).start()
|
||||||
if (gestureState.dy < -50) {
|
if (gestureState.dy < -50) {
|
||||||
Animated.spring(height, {
|
Animated.spring(height, {
|
||||||
useNativeDriver: false,
|
useNativeDriver: false,
|
||||||
toValue: getHeight(expandedHeight, screenHeight),
|
toValue: getHeight(expandedHeight, screenHeight),
|
||||||
}).start();
|
}).start()
|
||||||
} else if (gestureState.dy > 150) {
|
} else if (gestureState.dy > 150) {
|
||||||
height.setValue(getHeight(defaultHeight, screenHeight));
|
height.setValue(getHeight(defaultHeight, screenHeight))
|
||||||
offsetY.setValue(0);
|
offsetY.setValue(0)
|
||||||
onClose();
|
onClose()
|
||||||
} else {
|
} else {
|
||||||
Animated.spring(height, {
|
Animated.spring(height, {
|
||||||
useNativeDriver: false,
|
useNativeDriver: false,
|
||||||
toValue: getHeight(defaultHeight, screenHeight),
|
toValue: getHeight(defaultHeight, screenHeight),
|
||||||
}).start();
|
}).start()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onShouldBlockNativeResponder: () => {
|
onShouldBlockNativeResponder: () => {
|
||||||
return true;
|
return true
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
).current;
|
).current
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View {...panResponder.panHandlers}>
|
<View {...panResponder.panHandlers}>
|
||||||
|
@ -63,8 +56,8 @@ export const Knob = ({ offsetY, height, onClose }: KnobProps) => {
|
||||||
<Animated.View style={[styles.knob, knobStyles]} />
|
<Animated.View style={[styles.knob, knobStyles]} />
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
panContainer: {
|
panContainer: {
|
||||||
|
@ -86,4 +79,4 @@ const styles = StyleSheet.create({
|
||||||
shadowOffset: { width: 0, height: 0 },
|
shadowOffset: { width: 0, height: 0 },
|
||||||
shadowRadius: 5,
|
shadowRadius: 5,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import {
|
import {
|
||||||
SafeAreaView,
|
SafeAreaView,
|
||||||
Modal,
|
Modal,
|
||||||
|
@ -7,58 +7,47 @@ import {
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
TouchableOpacity,
|
TouchableOpacity,
|
||||||
View,
|
View,
|
||||||
} from 'react-native';
|
} from 'react-native'
|
||||||
import { KeyboardContext } from '../contexts/KeyboardContext';
|
import { KeyboardContext } from '../contexts/KeyboardContext'
|
||||||
import { useTimeout } from '../hooks/useTimeout';
|
import { useTimeout } from '../hooks/useTimeout'
|
||||||
|
|
||||||
type ModalWithBackdropProps = {
|
type ModalWithBackdropProps = {
|
||||||
isOpen: boolean;
|
isOpen: boolean
|
||||||
backdropPress: () => void;
|
backdropPress: () => void
|
||||||
children: React.ReactNode;
|
children: React.ReactNode
|
||||||
};
|
}
|
||||||
|
|
||||||
export const ModalWithBackdrop = ({
|
export const ModalWithBackdrop = ({ isOpen, backdropPress, children }: ModalWithBackdropProps) => {
|
||||||
isOpen,
|
const { height: screenHeight } = useWindowDimensions()
|
||||||
backdropPress,
|
const translateY = React.useRef(new Animated.Value(screenHeight)).current
|
||||||
children,
|
const { backdropColor } = React.useContext(KeyboardContext)
|
||||||
}: ModalWithBackdropProps) => {
|
const handleTimeout = useTimeout()
|
||||||
const { height: screenHeight } = useWindowDimensions();
|
|
||||||
const translateY = React.useRef(new Animated.Value(screenHeight)).current;
|
|
||||||
const { backdropColor } = React.useContext(KeyboardContext);
|
|
||||||
const handleTimeout = useTimeout();
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
Animated.spring(translateY, {
|
Animated.spring(translateY, {
|
||||||
toValue: isOpen ? 0 : screenHeight,
|
toValue: isOpen ? 0 : screenHeight,
|
||||||
useNativeDriver: true,
|
useNativeDriver: true,
|
||||||
}).start();
|
}).start()
|
||||||
}, [isOpen, screenHeight, translateY]);
|
}, [isOpen, screenHeight, translateY])
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
Animated.spring(translateY, {
|
Animated.spring(translateY, {
|
||||||
toValue: screenHeight,
|
toValue: screenHeight,
|
||||||
useNativeDriver: true,
|
useNativeDriver: true,
|
||||||
}).start();
|
}).start()
|
||||||
handleTimeout(() => backdropPress(), 200);
|
handleTimeout(() => backdropPress(), 200)
|
||||||
};
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal visible={isOpen} animationType="fade" transparent={true}>
|
<Modal visible={isOpen} animationType="fade" transparent={true}>
|
||||||
<TouchableOpacity
|
<TouchableOpacity style={styles.modalContainer} activeOpacity={1} onPress={handleClose}>
|
||||||
style={styles.modalContainer}
|
<View style={[styles.modalContainer, { backgroundColor: backdropColor }]}>
|
||||||
activeOpacity={1}
|
|
||||||
onPress={handleClose}
|
|
||||||
>
|
|
||||||
<View
|
|
||||||
style={[styles.modalContainer, { backgroundColor: backdropColor }]}
|
|
||||||
>
|
|
||||||
<SafeAreaView style={styles.modalContainer}>
|
<SafeAreaView style={styles.modalContainer}>
|
||||||
<TouchableOpacity activeOpacity={1}>
|
<TouchableOpacity activeOpacity={1}>
|
||||||
<Animated.View
|
<Animated.View
|
||||||
style={{
|
style={{
|
||||||
transform: [{ translateY }],
|
transform: [{ translateY }],
|
||||||
}}
|
}}>
|
||||||
>
|
|
||||||
{children}
|
{children}
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
@ -66,8 +55,8 @@ export const ModalWithBackdrop = ({
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
modalContainer: { flex: 1, justifyContent: 'flex-end' },
|
modalContainer: { flex: 1, justifyContent: 'flex-end' },
|
||||||
|
@ -80,4 +69,4 @@ const styles = StyleSheet.create({
|
||||||
shadowRadius: 5,
|
shadowRadius: 5,
|
||||||
elevation: 10,
|
elevation: 10,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
|
@ -1,17 +1,11 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import {
|
import { View, StyleSheet, TextInput, TouchableOpacity, FlatList } from 'react-native'
|
||||||
View,
|
import { KeyboardContext } from '../contexts/KeyboardContext'
|
||||||
StyleSheet,
|
import { Icon } from './Icon'
|
||||||
TextInput,
|
|
||||||
TouchableOpacity,
|
|
||||||
FlatList,
|
|
||||||
} from 'react-native';
|
|
||||||
import { KeyboardContext } from '../contexts/KeyboardContext';
|
|
||||||
import { Icon } from './Icon';
|
|
||||||
|
|
||||||
type SearchBarProps = {
|
type SearchBarProps = {
|
||||||
flatListRef: React.RefObject<FlatList>;
|
flatListRef: React.RefObject<FlatList>
|
||||||
};
|
}
|
||||||
|
|
||||||
export const SearchBar = ({ flatListRef }: SearchBarProps) => {
|
export const SearchBar = ({ flatListRef }: SearchBarProps) => {
|
||||||
const {
|
const {
|
||||||
|
@ -23,18 +17,18 @@ export const SearchBar = ({ flatListRef }: SearchBarProps) => {
|
||||||
searchBarStyles,
|
searchBarStyles,
|
||||||
searchBarTextStyles,
|
searchBarTextStyles,
|
||||||
searchBarPlaceholderColor,
|
searchBarPlaceholderColor,
|
||||||
} = React.useContext(KeyboardContext);
|
} = React.useContext(KeyboardContext)
|
||||||
const inputRef = React.useRef<TextInput>(null);
|
const inputRef = React.useRef<TextInput>(null)
|
||||||
|
|
||||||
const handleSearch = (text: string) => {
|
const handleSearch = (text: string) => {
|
||||||
setSearchPhrase(text);
|
setSearchPhrase(text)
|
||||||
};
|
}
|
||||||
const clearPhrase = () => {
|
const clearPhrase = () => {
|
||||||
setSearchPhrase('');
|
setSearchPhrase('')
|
||||||
inputRef.current?.blur();
|
inputRef.current?.blur()
|
||||||
setActiveCategoryIndex(0);
|
setActiveCategoryIndex(0)
|
||||||
flatListRef?.current?.scrollToIndex({ index: 0, animated: true });
|
flatListRef?.current?.scrollToIndex({ index: 0, animated: true })
|
||||||
};
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={[styles.container, searchBarStyles]}>
|
<View style={[styles.container, searchBarStyles]}>
|
||||||
|
@ -57,8 +51,8 @@ export const SearchBar = ({ flatListRef }: SearchBarProps) => {
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
|
@ -78,4 +72,4 @@ const styles = StyleSheet.create({
|
||||||
button: {
|
button: {
|
||||||
marginRight: 8,
|
marginRight: 8,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
|
@ -1,28 +1,28 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
|
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native'
|
||||||
import type { JsonEmoji } from '../types';
|
import type { JsonEmoji } from '../types'
|
||||||
|
|
||||||
export class SingleEmoji extends React.Component<{
|
export class SingleEmoji extends React.Component<{
|
||||||
item: JsonEmoji;
|
item: JsonEmoji
|
||||||
onPress: () => void;
|
onPress: () => void
|
||||||
emojiSize: number;
|
emojiSize: number
|
||||||
}> {
|
}> {
|
||||||
shouldComponentUpdate() {
|
shouldComponentUpdate() {
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
const { item, emojiSize, onPress } = this.props;
|
const { item, emojiSize, onPress } = this.props
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity onPress={onPress} style={styles.container}>
|
<TouchableOpacity onPress={onPress} style={styles.container}>
|
||||||
<View style={styles.iconContainer}>
|
<View style={styles.iconContainer}>
|
||||||
<Text style={{ fontSize: emojiSize }}>{item.emoji}</Text>
|
<Text style={{ fontSize: emojiSize }}>{item.emoji}</Text>
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: { flex: 1, padding: 8 },
|
container: { flex: 1, padding: 8 },
|
||||||
iconContainer: { justifyContent: 'center', alignItems: 'center' },
|
iconContainer: { justifyContent: 'center', alignItems: 'center' },
|
||||||
});
|
})
|
||||||
|
|
|
@ -1,62 +1,52 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import type { TextStyle, ViewStyle } from 'react-native';
|
import type { TextStyle, ViewStyle } from 'react-native'
|
||||||
import {
|
import { defaultKeyboardContext, defaultKeyboardValues } from './KeyboardProvider'
|
||||||
defaultKeyboardContext,
|
import type { CategoryTranslation, EmojiType, CategoryTypes, CategoryPosition } from '../types'
|
||||||
defaultKeyboardValues,
|
|
||||||
} from './KeyboardProvider';
|
|
||||||
import type {
|
|
||||||
CategoryTranslation,
|
|
||||||
EmojiType,
|
|
||||||
CategoryTypes,
|
|
||||||
CategoryPosition,
|
|
||||||
} from '../types';
|
|
||||||
|
|
||||||
export type OnEmojiSelected = (emoji: EmojiType) => void;
|
export type OnEmojiSelected = (emoji: EmojiType) => void
|
||||||
|
|
||||||
export type KeyboardProps = {
|
export type KeyboardProps = {
|
||||||
open: boolean;
|
open: boolean
|
||||||
onClose: () => void;
|
onClose: () => void
|
||||||
onEmojiSelected: OnEmojiSelected;
|
onEmojiSelected: OnEmojiSelected
|
||||||
emojiSize?: number;
|
emojiSize?: number
|
||||||
containerStyles?: ViewStyle;
|
containerStyles?: ViewStyle
|
||||||
knobStyles?: ViewStyle;
|
knobStyles?: ViewStyle
|
||||||
headerStyles?: TextStyle;
|
headerStyles?: TextStyle
|
||||||
expandable?: boolean;
|
expandable?: boolean
|
||||||
hideHeader?: boolean;
|
hideHeader?: boolean
|
||||||
defaultHeight?: number | string;
|
defaultHeight?: number | string
|
||||||
expandedHeight?: number | string;
|
expandedHeight?: number | string
|
||||||
backdropColor?: string;
|
backdropColor?: string
|
||||||
categoryColor?: string;
|
categoryColor?: string
|
||||||
activeCategoryColor?: string;
|
activeCategoryColor?: string
|
||||||
categoryContainerColor?: string;
|
categoryContainerColor?: string
|
||||||
activeCategoryContainerColor?: string;
|
activeCategoryContainerColor?: string
|
||||||
onCategoryChangeFailed?: (info: {
|
onCategoryChangeFailed?: (info: {
|
||||||
index: number;
|
index: number
|
||||||
highestMeasuredFrameIndex: number;
|
highestMeasuredFrameIndex: number
|
||||||
averageItemLength: number;
|
averageItemLength: number
|
||||||
}) => void;
|
}) => void
|
||||||
translation?: CategoryTranslation;
|
translation?: CategoryTranslation
|
||||||
disabledCategory?: CategoryTypes[];
|
disabledCategory?: CategoryTypes[]
|
||||||
enableRecentlyUsed?: boolean;
|
enableRecentlyUsed?: boolean
|
||||||
categoryPosition?: CategoryPosition;
|
categoryPosition?: CategoryPosition
|
||||||
enableSearchBar?: boolean;
|
enableSearchBar?: boolean
|
||||||
closeSearchColor?: string;
|
closeSearchColor?: string
|
||||||
searchBarStyles?: ViewStyle;
|
searchBarStyles?: ViewStyle
|
||||||
searchBarTextStyles?: TextStyle;
|
searchBarTextStyles?: TextStyle
|
||||||
searchBarPlaceholderColor?: string;
|
searchBarPlaceholderColor?: string
|
||||||
};
|
}
|
||||||
export type ContextValues = {
|
export type ContextValues = {
|
||||||
activeCategoryIndex: number;
|
activeCategoryIndex: number
|
||||||
setActiveCategoryIndex: (index: number) => void;
|
setActiveCategoryIndex: (index: number) => void
|
||||||
numberOfColumns: number;
|
numberOfColumns: number
|
||||||
width: number;
|
width: number
|
||||||
searchPhrase: string;
|
searchPhrase: string
|
||||||
setSearchPhrase: (phrase: string) => void;
|
setSearchPhrase: (phrase: string) => void
|
||||||
};
|
}
|
||||||
|
|
||||||
export const KeyboardContext = React.createContext<
|
export const KeyboardContext = React.createContext<Required<KeyboardProps> & ContextValues>({
|
||||||
Required<KeyboardProps> & ContextValues
|
|
||||||
>({
|
|
||||||
...defaultKeyboardContext,
|
...defaultKeyboardContext,
|
||||||
...defaultKeyboardValues,
|
...defaultKeyboardValues,
|
||||||
});
|
})
|
||||||
|
|
|
@ -1,18 +1,13 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react'
|
||||||
import { useWindowDimensions } from 'react-native';
|
import { useWindowDimensions } from 'react-native'
|
||||||
import {
|
import { KeyboardProps, ContextValues, KeyboardContext, OnEmojiSelected } from './KeyboardContext'
|
||||||
KeyboardProps,
|
import en from '../translation/en'
|
||||||
ContextValues,
|
import type { EmojiType } from '../types'
|
||||||
KeyboardContext,
|
|
||||||
OnEmojiSelected,
|
|
||||||
} from './KeyboardContext';
|
|
||||||
import en from '../translation/en';
|
|
||||||
import type { EmojiType } from '../types';
|
|
||||||
|
|
||||||
type ProviderProps = Partial<KeyboardProps> & {
|
type ProviderProps = Partial<KeyboardProps> & {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode
|
||||||
onEmojiSelected: OnEmojiSelected;
|
onEmojiSelected: OnEmojiSelected
|
||||||
};
|
}
|
||||||
|
|
||||||
export const defaultKeyboardContext: Required<KeyboardProps> = {
|
export const defaultKeyboardContext: Required<KeyboardProps> = {
|
||||||
open: false,
|
open: false,
|
||||||
|
@ -32,7 +27,7 @@ export const defaultKeyboardContext: Required<KeyboardProps> = {
|
||||||
categoryContainerColor: '#e3dbcd',
|
categoryContainerColor: '#e3dbcd',
|
||||||
activeCategoryContainerColor: '#ffffff',
|
activeCategoryContainerColor: '#ffffff',
|
||||||
onCategoryChangeFailed: (info) => {
|
onCategoryChangeFailed: (info) => {
|
||||||
console.warn(info);
|
console.warn(info)
|
||||||
},
|
},
|
||||||
translation: en,
|
translation: en,
|
||||||
disabledCategory: [],
|
disabledCategory: [],
|
||||||
|
@ -43,7 +38,7 @@ export const defaultKeyboardContext: Required<KeyboardProps> = {
|
||||||
searchBarStyles: {},
|
searchBarStyles: {},
|
||||||
searchBarTextStyles: {},
|
searchBarTextStyles: {},
|
||||||
searchBarPlaceholderColor: '#00000055',
|
searchBarPlaceholderColor: '#00000055',
|
||||||
};
|
}
|
||||||
|
|
||||||
export const defaultKeyboardValues: ContextValues = {
|
export const defaultKeyboardValues: ContextValues = {
|
||||||
activeCategoryIndex: 0,
|
activeCategoryIndex: 0,
|
||||||
|
@ -52,25 +47,19 @@ export const defaultKeyboardValues: ContextValues = {
|
||||||
width: 0,
|
width: 0,
|
||||||
searchPhrase: '',
|
searchPhrase: '',
|
||||||
setSearchPhrase: (_phrase: string) => {},
|
setSearchPhrase: (_phrase: string) => {},
|
||||||
};
|
}
|
||||||
|
|
||||||
export const KeyboardProvider: React.FC<ProviderProps> = React.memo((props) => {
|
export const KeyboardProvider: React.FC<ProviderProps> = React.memo((props) => {
|
||||||
const { width } = useWindowDimensions();
|
const { width } = useWindowDimensions()
|
||||||
const [activeCategoryIndex, setActiveCategoryIndex] = React.useState(0);
|
const [activeCategoryIndex, setActiveCategoryIndex] = React.useState(0)
|
||||||
const [searchPhrase, setSearchPhrase] = React.useState('');
|
const [searchPhrase, setSearchPhrase] = React.useState('')
|
||||||
const numberOfColumns = React.useRef<number>(
|
const numberOfColumns = React.useRef<number>(
|
||||||
Math.floor(
|
Math.floor(width / ((props.emojiSize ? props.emojiSize : defaultKeyboardContext.emojiSize) * 2))
|
||||||
width /
|
|
||||||
((props.emojiSize
|
|
||||||
? props.emojiSize
|
|
||||||
: defaultKeyboardContext.emojiSize) *
|
|
||||||
2)
|
|
||||||
)
|
)
|
||||||
);
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (props.open) setActiveCategoryIndex(0);
|
if (props.open) setActiveCategoryIndex(0)
|
||||||
setSearchPhrase('');
|
setSearchPhrase('')
|
||||||
}, [props.open]);
|
}, [props.open])
|
||||||
|
|
||||||
const value: Required<KeyboardProps> & ContextValues = {
|
const value: Required<KeyboardProps> & ContextValues = {
|
||||||
...defaultKeyboardContext,
|
...defaultKeyboardContext,
|
||||||
|
@ -82,12 +71,8 @@ export const KeyboardProvider: React.FC<ProviderProps> = React.memo((props) => {
|
||||||
width,
|
width,
|
||||||
searchPhrase,
|
searchPhrase,
|
||||||
setSearchPhrase,
|
setSearchPhrase,
|
||||||
};
|
}
|
||||||
return (
|
return <KeyboardContext.Provider value={value}>{props.children}</KeyboardContext.Provider>
|
||||||
<KeyboardContext.Provider value={value}>
|
})
|
||||||
{props.children}
|
|
||||||
</KeyboardContext.Provider>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
KeyboardProvider.displayName = 'KeyboardProvider';
|
KeyboardProvider.displayName = 'KeyboardProvider'
|
||||||
|
|
|
@ -1,19 +1,17 @@
|
||||||
import { MutableRefObject, useCallback, useEffect, useRef } from 'react';
|
import { MutableRefObject, useCallback, useEffect, useRef } from 'react'
|
||||||
|
|
||||||
export const useTimeout = () => {
|
export const useTimeout = () => {
|
||||||
const timeoutRef = useRef(null) as MutableRefObject<ReturnType<
|
const timeoutRef = useRef(null) as MutableRefObject<ReturnType<typeof setTimeout> | null>
|
||||||
typeof setTimeout
|
|
||||||
> | null>;
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
if (timeoutRef.current) {
|
if (timeoutRef.current) {
|
||||||
clearTimeout(timeoutRef.current);
|
clearTimeout(timeoutRef.current)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}, []);
|
}, [])
|
||||||
|
|
||||||
return useCallback((callback: () => void, time: number) => {
|
return useCallback((callback: () => void, time: number) => {
|
||||||
timeoutRef.current = setTimeout(callback, time);
|
timeoutRef.current = setTimeout(callback, time)
|
||||||
}, []);
|
}, [])
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { EmojiPicker } from './EmojiPicker';
|
import { EmojiPicker } from './EmojiPicker'
|
||||||
import { EmojiKeyboard } from './EmojiKeyboard';
|
import { EmojiKeyboard } from './EmojiKeyboard'
|
||||||
import en from './translation/en';
|
import en from './translation/en'
|
||||||
import pl from './translation/pl';
|
import pl from './translation/pl'
|
||||||
|
|
||||||
export { EmojiKeyboard };
|
export { EmojiKeyboard }
|
||||||
export { en, pl };
|
export { en, pl }
|
||||||
|
|
||||||
export default EmojiPicker;
|
export default EmojiPicker
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import type { JsonEmoji } from 'src/types';
|
import type { JsonEmoji } from 'src/types'
|
||||||
|
|
||||||
export type RecentEmojiState = {
|
export type RecentEmojiState = {
|
||||||
recentlyUsed: JsonEmoji[];
|
recentlyUsed: JsonEmoji[]
|
||||||
};
|
}
|
||||||
|
|
||||||
export type RecentEmojiAction =
|
export type RecentEmojiAction =
|
||||||
| { type: 'RECENT_EMOJI_ADD'; payload: JsonEmoji }
|
| { type: 'RECENT_EMOJI_ADD'; payload: JsonEmoji }
|
||||||
| { type: 'RECENT_EMOJI_REMOVE'; payload: JsonEmoji }
|
| { type: 'RECENT_EMOJI_REMOVE'; payload: JsonEmoji }
|
||||||
| { type: 'RECENT_EMOJI_CLEAR' };
|
| { type: 'RECENT_EMOJI_CLEAR' }
|
||||||
|
|
||||||
export default function recentEmojiReducer(
|
export default function recentEmojiReducer(
|
||||||
state: RecentEmojiState,
|
state: RecentEmojiState,
|
||||||
|
@ -18,18 +18,18 @@ export default function recentEmojiReducer(
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
recentlyUsed: [action.payload, ...filterEmoji(state, action.payload)],
|
recentlyUsed: [action.payload, ...filterEmoji(state, action.payload)],
|
||||||
};
|
}
|
||||||
case 'RECENT_EMOJI_REMOVE':
|
case 'RECENT_EMOJI_REMOVE':
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
recentlyUsed: filterEmoji(state, action.payload),
|
recentlyUsed: filterEmoji(state, action.payload),
|
||||||
};
|
}
|
||||||
case 'RECENT_EMOJI_CLEAR':
|
case 'RECENT_EMOJI_CLEAR':
|
||||||
return { ...state, recentlyUsed: [] };
|
return { ...state, recentlyUsed: [] }
|
||||||
default:
|
default:
|
||||||
return state;
|
return state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const filterEmoji = (state: RecentEmojiState, emoji: JsonEmoji) =>
|
const filterEmoji = (state: RecentEmojiState, emoji: JsonEmoji) =>
|
||||||
state.recentlyUsed.filter((usedEmoji) => usedEmoji.emoji !== emoji.emoji);
|
state.recentlyUsed.filter((usedEmoji) => usedEmoji.emoji !== emoji.emoji)
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
import recentEmojiReducer, {
|
import recentEmojiReducer, { RecentEmojiAction, RecentEmojiState } from './RecentEmojiReducer'
|
||||||
RecentEmojiAction,
|
|
||||||
RecentEmojiState,
|
|
||||||
} from './RecentEmojiReducer';
|
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// - combine Keyboard reducers in future
|
// - combine Keyboard reducers in future
|
||||||
|
|
||||||
export type KeyboardState = RecentEmojiState;
|
export type KeyboardState = RecentEmojiState
|
||||||
export type KeyboardAction = RecentEmojiAction;
|
export type KeyboardAction = RecentEmojiAction
|
||||||
export default recentEmojiReducer;
|
export default recentEmojiReducer
|
||||||
|
|
|
@ -1,29 +1,29 @@
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react'
|
||||||
import type { KeyboardAction, KeyboardState } from './reducers';
|
import type { KeyboardAction, KeyboardState } from './reducers'
|
||||||
import keyboardReducer from './reducers';
|
import keyboardReducer from './reducers'
|
||||||
|
|
||||||
let globalKeyboardState: KeyboardState = {
|
let globalKeyboardState: KeyboardState = {
|
||||||
recentlyUsed: [],
|
recentlyUsed: [],
|
||||||
};
|
}
|
||||||
|
|
||||||
type KeyboardStateSetter = () => any;
|
type KeyboardStateSetter = () => any
|
||||||
const keyboardStateListeners = new Set<KeyboardStateSetter>();
|
const keyboardStateListeners = new Set<KeyboardStateSetter>()
|
||||||
|
|
||||||
const setKeyboardState = (action: KeyboardAction) => {
|
const setKeyboardState = (action: KeyboardAction) => {
|
||||||
globalKeyboardState = keyboardReducer(globalKeyboardState, action);
|
globalKeyboardState = keyboardReducer(globalKeyboardState, action)
|
||||||
keyboardStateListeners.forEach((listener) => listener());
|
keyboardStateListeners.forEach((listener) => listener())
|
||||||
};
|
}
|
||||||
|
|
||||||
export const useKeyboardStore = () => {
|
export const useKeyboardStore = () => {
|
||||||
const [keyboardState, setState] = useState(globalKeyboardState);
|
const [keyboardState, setState] = useState(globalKeyboardState)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const listener = () => setState(globalKeyboardState);
|
const listener = () => setState(globalKeyboardState)
|
||||||
keyboardStateListeners.add(listener);
|
keyboardStateListeners.add(listener)
|
||||||
return () => {
|
return () => {
|
||||||
keyboardStateListeners.delete(listener);
|
keyboardStateListeners.delete(listener)
|
||||||
};
|
}
|
||||||
}, [keyboardState]);
|
}, [keyboardState])
|
||||||
|
|
||||||
return { keyboardState, setKeyboardState };
|
return { keyboardState, setKeyboardState }
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { CategoryTranslation } from '../types';
|
import type { CategoryTranslation } from '../types'
|
||||||
|
|
||||||
export const en: CategoryTranslation = {
|
export const en: CategoryTranslation = {
|
||||||
recently_used: 'Recently used',
|
recently_used: 'Recently used',
|
||||||
|
@ -12,5 +12,5 @@ export const en: CategoryTranslation = {
|
||||||
symbols: 'Symbols',
|
symbols: 'Symbols',
|
||||||
flags: 'Flags',
|
flags: 'Flags',
|
||||||
search: 'Search',
|
search: 'Search',
|
||||||
};
|
}
|
||||||
export default en;
|
export default en
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { CategoryTranslation } from '../types';
|
import type { CategoryTranslation } from '../types'
|
||||||
|
|
||||||
const pl: CategoryTranslation = {
|
const pl: CategoryTranslation = {
|
||||||
recently_used: 'Ostatnio używane',
|
recently_used: 'Ostatnio używane',
|
||||||
|
@ -12,5 +12,5 @@ const pl: CategoryTranslation = {
|
||||||
symbols: 'Symbole',
|
symbols: 'Symbole',
|
||||||
flags: 'Flagi',
|
flags: 'Flagi',
|
||||||
search: 'Szukaj',
|
search: 'Szukaj',
|
||||||
};
|
}
|
||||||
export default pl;
|
export default pl
|
||||||
|
|
44
src/types.ts
44
src/types.ts
|
@ -10,39 +10,39 @@ export const CATEGORIES_NAVIGATION = [
|
||||||
{ icon: 'Flag', category: 'flags' },
|
{ icon: 'Flag', category: 'flags' },
|
||||||
{ icon: 'Clock', category: 'recently_used' },
|
{ icon: 'Clock', category: 'recently_used' },
|
||||||
{ icon: 'Search', category: 'search' },
|
{ icon: 'Search', category: 'search' },
|
||||||
] as const;
|
] as const
|
||||||
|
|
||||||
export type IconNames = typeof CATEGORIES_NAVIGATION[number]['icon'];
|
export type IconNames = typeof CATEGORIES_NAVIGATION[number]['icon']
|
||||||
export type CategoryTypes = typeof CATEGORIES_NAVIGATION[number]['category'];
|
export type CategoryTypes = typeof CATEGORIES_NAVIGATION[number]['category']
|
||||||
|
|
||||||
export const CATEGORIES: readonly CategoryTypes[] = CATEGORIES_NAVIGATION.map(
|
export const CATEGORIES: readonly CategoryTypes[] = CATEGORIES_NAVIGATION.map(
|
||||||
({ category }) => category
|
({ category }) => category
|
||||||
);
|
)
|
||||||
|
|
||||||
export type JsonEmoji = {
|
export type JsonEmoji = {
|
||||||
emoji: string;
|
emoji: string
|
||||||
name: string;
|
name: string
|
||||||
v: string;
|
v: string
|
||||||
};
|
}
|
||||||
export type EmojiType = {
|
export type EmojiType = {
|
||||||
emoji: string;
|
emoji: string
|
||||||
name: string;
|
name: string
|
||||||
slug: string;
|
slug: string
|
||||||
unicode_version: string;
|
unicode_version: string
|
||||||
};
|
}
|
||||||
|
|
||||||
export type CategoryPosition = 'floating' | 'top' | 'bottom';
|
export type CategoryPosition = 'floating' | 'top' | 'bottom'
|
||||||
|
|
||||||
export type CategoryNavigationItem = {
|
export type CategoryNavigationItem = {
|
||||||
icon: IconNames;
|
icon: IconNames
|
||||||
category: CategoryTypes;
|
category: CategoryTypes
|
||||||
};
|
}
|
||||||
|
|
||||||
export type CategoryTranslation = {
|
export type CategoryTranslation = {
|
||||||
[key in CategoryTypes]: string;
|
[key in CategoryTypes]: string
|
||||||
};
|
}
|
||||||
|
|
||||||
export type EmojisByCategory = {
|
export type EmojisByCategory = {
|
||||||
title: CategoryTypes;
|
title: CategoryTypes
|
||||||
data: EmojiType[];
|
data: EmojiType[]
|
||||||
};
|
}
|
||||||
|
|
25
src/utils.ts
25
src/utils.ts
|
@ -1,29 +1,22 @@
|
||||||
import { CATEGORIES, CategoryTypes, JsonEmoji } from './types';
|
import { CATEGORIES, CategoryTypes, JsonEmoji } from './types'
|
||||||
|
|
||||||
export const getHeight = (value: string | number, screenHeight: number) =>
|
export const getHeight = (value: string | number, screenHeight: number) =>
|
||||||
typeof value === 'number'
|
typeof value === 'number' ? value : (screenHeight / 100) * parseInt(value.replace('%', ''), 10)
|
||||||
? value
|
|
||||||
: (screenHeight / 100) * parseInt(value.replace('%', ''), 10);
|
|
||||||
|
|
||||||
export const exhaustiveTypeCheck = (arg: never, strict = true) => {
|
export const exhaustiveTypeCheck = (arg: never, strict = true) => {
|
||||||
console.log(`unhandled union case for : ${arg}`);
|
console.log(`unhandled union case for : ${arg}`)
|
||||||
if (strict) {
|
if (strict) {
|
||||||
throw new Error(`unhandled union case for : ${arg}`);
|
throw new Error(`unhandled union case for : ${arg}`)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export const parseEmoji = (emoji: JsonEmoji) => ({
|
export const parseEmoji = (emoji: JsonEmoji) => ({
|
||||||
name: emoji.name,
|
name: emoji.name,
|
||||||
emoji: emoji.emoji,
|
emoji: emoji.emoji,
|
||||||
unicode_version: emoji.v,
|
unicode_version: emoji.v,
|
||||||
slug: emoji.name.replace(' ', '_'),
|
slug: emoji.name.replace(' ', '_'),
|
||||||
});
|
})
|
||||||
|
|
||||||
export const getCategoryIndex = (
|
export const getCategoryIndex = (disabledCategory: CategoryTypes[], category: CategoryTypes) => ({
|
||||||
disabledCategory: CategoryTypes[],
|
index: CATEGORIES.filter((name) => !disabledCategory.includes(name)).indexOf(category),
|
||||||
category: CategoryTypes
|
})
|
||||||
) => ({
|
|
||||||
index: CATEGORIES.filter((name) => !disabledCategory.includes(name)).indexOf(
|
|
||||||
category
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
{
|
{
|
||||||
"extends": "./tsconfig",
|
"extends": "./tsconfig",
|
||||||
"exclude": ["example"]
|
"exclude": ["example"]
|
||||||
|
|
|
@ -1837,6 +1837,11 @@
|
||||||
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
|
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
|
||||||
integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==
|
integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==
|
||||||
|
|
||||||
|
"@twgdev/prettier-config@^1.0.2":
|
||||||
|
version "1.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@twgdev/prettier-config/-/prettier-config-1.0.2.tgz#5a313df4341efb2221b5e7b4c52153e86861b1dc"
|
||||||
|
integrity sha512-79UJ8Cp+dIoE8V5g8y2SDvshhGQsGaDkTdY3YVbbMzTUW/Bdv/0AOFASNNGKXy7pfkcukeUD27cgRECAU4Swyg==
|
||||||
|
|
||||||
"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7":
|
"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7":
|
||||||
version "7.1.14"
|
version "7.1.14"
|
||||||
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.14.tgz#faaeefc4185ec71c389f4501ee5ec84b170cc402"
|
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.14.tgz#faaeefc4185ec71c389f4501ee5ec84b170cc402"
|
||||||
|
|
Loading…
Reference in New Issue