Skip to content

Commit

Permalink
feat: adding custom button feature
Browse files Browse the repository at this point in the history
  • Loading branch information
DominikDanielewicz committed Mar 10, 2024
1 parent 31aa092 commit c9b3ba9
Show file tree
Hide file tree
Showing 14 changed files with 216 additions and 4 deletions.
Binary file added docs/assets/img/custom-button-preview-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/img/custom-button-preview-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/img/custom-button-preview-3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 46 additions & 0 deletions docs/docs/documentation/Examples/custom-button.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
sidebar_position: 13
title: Custom Button
---

import preview1 from '../../../assets/img/custom-button-preview-1.png'
import preview2 from '../../../assets/img/custom-button-preview-2.png'
import preview3 from '../../../assets/img/custom-button-preview-3.png'

:::info
To preview app with this example, clone [**github repo**](https://github.com/TheWidlarzGroup/rn-emoji-keyboard.git) and run `yarn example ios` or `yarn example android`.
:::

### Usage

We've introduced a custom button feature to provide you with the flexibility to add your unique functionality to our interface. This feature allows you to, for example, add a function that deletes the previously used emoji, enhancing user interaction based on your application's specific needs.

If you want to reveal the custom button, pass `enableCustomButton` prop. After that, use the `onCustomButtonPress` callback to define the specific action you want the custom button to perform.

If search bar is enabled, custom button shows next to it.

```jsx
import EmojiPicker from 'rn-emoji-keyboard'

const ExampleComponent = () => {
// ...

return (
<EmojiPicker
open={isOpen}
onClose={handleOnClose}
onEmojiSelected={handleOnEmojiSelected}
// add props below
enableSearchBar
enableCustomButton
onCustomButtonPress={() => deleteLastEmoji()}
/>
)
}
```

<div className="gallery">
<img src={preview1} alt="First Image" />
<img src={preview2} alt="Second Image" />
<img src={preview3} alt="Third Image" />
</div>
31 changes: 31 additions & 0 deletions docs/src/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,34 @@
font-weight: 700;
src: local('JetBrainsMono'), url(../../assets/fonts/JetBrainsMono-Bold.woff2) format('woff2');
}

.gallery {
display: flex;
justify-content: space-between;
align-items: center;
flex-direction: row;
}

.gallery img {
width: 32%;
margin-right: 2%;
}

.gallery img:last-child {
margin-right: 0;
}

@media (max-width: 768px) {
.gallery {
flex-direction: column;
}
.gallery img {
width: 100%;
margin-right: 0px;
margin-bottom: 20px;
}

.gallery img:last-child {
margin-right: 0;
}
}
41 changes: 41 additions & 0 deletions example/app/(examples)/custom-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Button } from 'example/src/components/Button'
import React from 'react'
import { Results } from 'example/src/components/Results'
import EmojiPicker, { type EmojiType } from 'rn-emoji-keyboard'

export default function () {
const [result, setResult] = React.useState<string>()
const [isModalOpen, setIsModalOpen] = React.useState<boolean>(false)

const handlePick = (emoji: EmojiType) => {
console.log(emoji)
setResult(emoji.emoji)
setIsModalOpen((prev) => !prev)
}

const deleteLastEmoji = () => {
if (result) {
let arrayFromString = Array.from(result)
arrayFromString.pop()
setResult(arrayFromString.join(''))
}
}

return (
<>
<Results label={result} />
<Button onPress={() => setIsModalOpen(true)} label="Open" />

<EmojiPicker
onEmojiSelected={handlePick}
open={isModalOpen}
onClose={() => setIsModalOpen(false)}
enableSearchBar
enableCustomButton
onCustomButtonPress={() => deleteLastEmoji()}
allowMultipleSelections
categoryPosition="bottom"
/>
</>
)
}
2 changes: 1 addition & 1 deletion example/app/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as React from 'react'

import { StyleSheet, View } from 'react-native'
import { Link } from 'example/src/components/Link'
import { Stack } from 'expo-router'
Expand All @@ -18,6 +17,7 @@ export const screens = {
'/search': 'Search Bar',
'/selected-emojis': 'Selected Emojis',
'/translated': 'Translated',
'/custom-button': 'Custom Button',
} as const

export default function App() {
Expand Down
2 changes: 2 additions & 0 deletions src/EmojiPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const EmojiPicker = ({
onRequestClose,
open,
onClose,
onCustomButtonPress,
expandable = defaultKeyboardContext.expandable,
defaultHeight = defaultKeyboardContext.defaultHeight,
allowMultipleSelections = false,
Expand Down Expand Up @@ -51,6 +52,7 @@ export const EmojiPicker = ({
}}
open={open}
onClose={close}
onCustomButtonPress={onCustomButtonPress}
expandable={expandable}
defaultHeight={defaultHeight}
{...props}
Expand Down
Binary file added src/assets/icons/backspace.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
55 changes: 55 additions & 0 deletions src/components/CustomButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import React from 'react'
import { View, Pressable, StyleSheet } from 'react-native'
import { KeyboardContext } from '../contexts/KeyboardContext'
import { Icon } from './Icon'

type CustomButtonType = {
customButtonPressHandler: () => void
}

export const CustomButton = ({ customButtonPressHandler }: CustomButtonType) => {
const { theme } = React.useContext(KeyboardContext)
return (
<View style={styles.buttonContainer}>
<Pressable
onPress={customButtonPressHandler}
style={({ pressed }) => [
{
backgroundColor: pressed
? theme.customButton.backgroundPressed
: theme.customButton.background,
padding: 10,
borderRadius: 100,
},
styles.button,
]}
>
{({ pressed }) => (
<Icon
iconName={'Backspace'}
isActive={pressed}
normalColor={theme.customButton.icon}
activeColor={theme.customButton.iconPressed}
/>
)}
</Pressable>
</View>
)
}

const styles = StyleSheet.create({
buttonContainer: {
marginTop: 16,
marginHorizontal: 16,
borderRadius: 100,
flexDirection: 'row',
justifyContent: 'flex-end',
},
button: {
justifyContent: 'center',
alignItems: 'center',
},
text: {
color: 'white',
},
})
21 changes: 19 additions & 2 deletions src/components/EmojiStaticKeyboard.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as React from 'react'

import {
StyleSheet,
View,
Expand All @@ -18,6 +17,7 @@ import { SearchBar } from './SearchBar'
import { useKeyboardStore } from '../store/useKeyboardStore'
import { ConditionalContainer } from './ConditionalContainer'
import { SkinTones } from './SkinTones'
import { CustomButton } from './CustomButton'

const CATEGORY_ELEMENT_WIDTH = 37
const isAndroid = Platform.OS === 'android'
Expand All @@ -31,13 +31,15 @@ export const EmojiStaticKeyboard = React.memo(
enableCategoryChangeGesture,
categoryPosition,
enableSearchBar,
enableCustomButton,
searchPhrase,
renderList,
disableSafeArea,
theme,
styles: themeStyles,
shouldAnimateScroll,
enableCategoryChangeAnimation,
onCustomButtonPress,
width,
setWidth,
} = React.useContext(KeyboardContext)
Expand Down Expand Up @@ -134,7 +136,18 @@ export const EmojiStaticKeyboard = React.memo(
)}
>
<>
{enableSearchBar && <SearchBar />}
<View
style={
categoryPosition === 'top'
? [styles.searchContainer, { marginBottom: 16 }]
: styles.searchContainer
}
>
{enableSearchBar && <SearchBar />}
{enableCustomButton && (
<CustomButton customButtonPressHandler={onCustomButtonPress} />
)}
</View>
<Animated.FlatList<EmojisByCategory>
extraData={[keyboardState.recentlyUsed.length, searchPhrase]}
data={renderList}
Expand Down Expand Up @@ -171,6 +184,10 @@ const styles = StyleSheet.create({
flex: 1,
borderRadius: 16,
},
searchContainer: {
flexDirection: 'row',
justifyContent: 'flex-end',
},
containerReverse: { flexDirection: 'column-reverse' },
containerShadow: {
shadowColor: 'black',
Expand Down
4 changes: 3 additions & 1 deletion src/components/Icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const Icon = ({
normalColor,
activeColor,
}: {
iconName: IconNames | 'Close' | 'QuestionMark'
iconName: IconNames | 'Close' | 'QuestionMark' | 'Backspace'
isActive: boolean
normalColor: string
activeColor: string
Expand Down Expand Up @@ -43,6 +43,8 @@ export const Icon = ({
return <PngIcon fill={color} source={require('../assets/icons/clock.png')} />
case 'QuestionMark':
return <PngIcon fill={color} source={require('../assets/icons/questionMark.png')} />
case 'Backspace':
return <PngIcon fill={color} source={require('../assets/icons/backspace.png')} />
default:
exhaustiveTypeCheck(iconName)
return null
Expand Down
2 changes: 2 additions & 0 deletions src/components/SearchBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export const SearchBar = () => {
setShouldAnimateScroll(enableSearchAnimation)
}
}

const clearPhrase = () => {
setSearchPhrase('')
clearEmojiTonesData()
Expand Down Expand Up @@ -82,6 +83,7 @@ const styles = StyleSheet.create({
borderColor: '#00000011',
flexDirection: 'row',
alignItems: 'center',
flex: 1,
},
input: {
paddingVertical: 8,
Expand Down
16 changes: 16 additions & 0 deletions src/contexts/KeyboardContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ export type Theme = {
placeholder: string
icon: string
}
customButton: {
icon: string
iconPressed: string
background: string
backgroundPressed: string
}
emoji: {
selected: string
}
Expand All @@ -76,6 +82,8 @@ export type KeyboardProps = {
enableRecentlyUsed?: boolean
categoryPosition?: CategoryPosition
enableSearchBar?: boolean
enableCustomButton?: boolean
onCustomButtonPress?: () => void
categoryOrder?: CategoryTypes[]
onRequestClose?: () => void
disableSafeArea?: boolean
Expand Down Expand Up @@ -140,6 +148,12 @@ export const defaultTheme: Theme = {
icon: '#00000055',
background: '#00000011',
},
customButton: {
icon: '#000000',
iconPressed: '#005b96',
background: '#00000011',
backgroundPressed: '#00000016',
},
emoji: {
selected: '#e3dbcd',
},
Expand All @@ -163,6 +177,8 @@ export const defaultKeyboardContext: Required<KeyboardProps> & {
enableRecentlyUsed: false,
categoryPosition: 'floating',
enableSearchBar: false,
enableCustomButton: false,
onCustomButtonPress: () => {},
categoryOrder: [...CATEGORIES],
onRequestClose: () => {},
disableSafeArea: false,
Expand Down

0 comments on commit c9b3ba9

Please sign in to comment.