Skip to content

Commit

Permalink
feat!: add support of custom emojis (slack like)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lucas Bourgeois committed Oct 2, 2024
1 parent ae22fa1 commit e4116d5
Show file tree
Hide file tree
Showing 53 changed files with 334 additions and 119 deletions.
2 changes: 1 addition & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# readme

README.md
README.md
18 changes: 14 additions & 4 deletions docs/docs/api/emojisData.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,25 @@ import { emojisByCategory } from 'rn-emoji-keyboard'
Here is the EmojisData structure explained as Typescript code

```ts
type EmojiType = {
emoji: string // Visual representation of emoji

export type EmojiTypeBase = {
name: string
slug: string
unicode_version: string
toneEnabled: boolean
alreadySelected?: boolean
}

export type UnicodeEmojiType = EmojiTypeBase & {
emoji: string // Visual representation of emoji
toneEnabled: boolean
unicode_version: string
}

export type UriEmojiType = EmojiTypeBase & {
uri: string // Distant URI / base64 / Image.resolveAssetSource(require('asset/path/emote.ext').uri
}

export type EmojiType = UnicodeEmojiType | UriEmojiType

type EmojisByCategory = {
title: CategoryTypes
data: JsonEmoji[]
Expand Down
33 changes: 31 additions & 2 deletions docs/docs/documentation/Examples/emojis-data.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,48 @@ To preview app with this example, clone [**github repo**](https://github.com/The

It's possible to pass your own set of emojis. You have to keep in mind that types and category titles must match the ones that we are using. In the example you can see custom emojis set that contains only emojis with unicode version === 11.

```jsx
Passing your set of emojis allows you to support translated keywords, names and custom emojis

```tsx
import EmojiPicker, { emojisByCategory } from 'rn-emoji-keyboard'
import { isUnicodeEmoji } from '../../../src/utils/parseEmoji'
import type { EmojisByCategory } from 'src/types'
import { Image } from 'react-native'

const getCustomEmojis = () => {
const newEmojiSet: EmojisByCategory[] = []

// Filter in categories, emojis version equal to unicode 11
for (const [, value] of Object.entries(emojisByCategory)) {
const newData = value.data.filter((emoji) => parseFloat(emoji.v) === 11)
const newData = value.data.filter(
(emoji) => isUnicodeEmoji(emoji) && parseFloat(emoji.v) === 11,
)
newEmojiSet.push({
title: value.title,
data: newData,
})
}

// Add in custom category URI sourced emojis
// Can be either a distant https:// or a base64 formatted image or a resolved image asset
const customCategoryIndex = emojisByCategory.findIndex(({ title }) => title === 'custom')
newEmojiSet[customCategoryIndex]!.data = [
{
uri: Image.resolveAssetSource(require('example/assets/custom/shhhh.webp')).uri,
keywords: ['shhhh', 'face'],
name: 'shhhh',
},
{
uri: Image.resolveAssetSource(require('example/assets/custom/silly.webp')).uri,
keywords: ['silly', 'face'],
name: 'silly',
},
{
uri: Image.resolveAssetSource(require('example/assets/custom/woah.webp')).uri,
keywords: ['woaah', 'face'],
name: 'woaah',
},
]
return newEmojiSet
}

Expand Down
8 changes: 4 additions & 4 deletions example/app/(examples)/basic.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { Button } from 'example/src/components/Button'
import { Results } from 'example/src/components/Results'
import React from 'react'
import EmojiPicker, { type EmojiType } from 'rn-emoji-keyboard'
import { Result } from 'example/src/components/Result'

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

const handlePick = (emoji: EmojiType) => {
console.log(emoji)
setResult(emoji.emoji)
setResult(emoji)
setIsModalOpen((prev) => !prev)
}
return (
<>
<Results label={result} />
{result && <Result emoji={result} />}
<Button onPress={() => setIsModalOpen(true)} label="Open" />

<EmojiPicker
Expand Down
8 changes: 4 additions & 4 deletions example/app/(examples)/category-bottom.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { Button } from 'example/src/components/Button'
import { Results } from 'example/src/components/Results'
import { Result } from 'example/src/components/Result'
import React from 'react'
import EmojiPicker, { type EmojiType } from 'rn-emoji-keyboard'

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

const handlePick = (emoji: EmojiType) => {
console.log(emoji)
setResult(emoji.emoji)
setResult(emoji)
setIsModalOpen((prev) => !prev)
}
return (
<>
<Results label={result} />
{result && <Result emoji={result} />}
<Button onPress={() => setIsModalOpen(true)} label="Open" />

<EmojiPicker
Expand Down
8 changes: 4 additions & 4 deletions example/app/(examples)/category-top.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { Button } from 'example/src/components/Button'
import { Results } from 'example/src/components/Results'
import { Result } from 'example/src/components/Result'
import React from 'react'
import EmojiPicker, { type EmojiType } from 'rn-emoji-keyboard'

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

const handlePick = (emoji: EmojiType) => {
console.log(emoji)
setResult(emoji.emoji)
setResult(emoji)
setIsModalOpen((prev) => !prev)
}
return (
<>
<Results label={result} />
{result && <Result emoji={result} />}
<Button onPress={() => setIsModalOpen(true)} label="Open" />

<EmojiPicker
Expand Down
14 changes: 7 additions & 7 deletions example/app/(examples)/custom-buttons.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
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'
import { DeleteButton } from '../../../src/components/DeleteButton'
import { Results } from '../../src/components/Results'

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

const handlePick = (emoji: EmojiType) => {
console.log(emoji)
setResult(emoji.emoji)
setResults([...results, emoji])
setIsModalOpen((prev) => !prev)
}

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

return (
<>
<Results label={result} />
{results?.length && <Results emojis={results} />}
<Button onPress={() => setIsModalOpen(true)} label="Open" />

<EmojiPicker
Expand Down
8 changes: 4 additions & 4 deletions example/app/(examples)/dark.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { Button } from 'example/src/components/Button'
import { Results } from 'example/src/components/Results'
import React from 'react'
import EmojiPicker, { type EmojiType } from 'rn-emoji-keyboard'
import { Result } from '../../src/components/Result'

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

const handlePick = (emoji: EmojiType) => {
console.log(emoji)
setResult(emoji.emoji)
setResult(emoji)
setIsModalOpen((prev) => !prev)
}
return (
<>
<Results label={result} />
{result && <Result emoji={result} />}
<Button onPress={() => setIsModalOpen(true)} label="Open" />

<EmojiPicker
Expand Down
8 changes: 4 additions & 4 deletions example/app/(examples)/disabled-categories.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { Button } from 'example/src/components/Button'
import { Results } from 'example/src/components/Results'
import { Result } from 'example/src/components/Result'
import React from 'react'
import EmojiPicker, { type EmojiType } from 'rn-emoji-keyboard'

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

const handlePick = (emoji: EmojiType) => {
console.log(emoji)
setResult(emoji.emoji)
setResult(emoji)
setIsModalOpen((prev) => !prev)
}
return (
<>
<Results label={result} />
{result && <Result emoji={result} />}
<Button onPress={() => setIsModalOpen(true)} label="Open" />

<EmojiPicker
Expand Down
36 changes: 30 additions & 6 deletions example/app/(examples)/emoji-data.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,60 @@
import { Button } from 'example/src/components/Button'
import { Results } from 'example/src/components/Results'
import React from 'react'
import EmojiPicker, {
emojisByCategory,
type EmojiType,
type EmojisByCategory,
type EmojiType,
} from 'rn-emoji-keyboard'
import { Result } from '../../src/components/Result'
import { Image } from 'react-native'
import { isUnicodeEmoji } from '../../../src/utils/typeguards'

const getCustomEmojis = () => {
const newEmojiSet: EmojisByCategory[] = []

for (const [, value] of Object.entries(emojisByCategory)) {
const newData = value.data.filter((emoji) => parseFloat(emoji.v) === 11)
const newData = value.data.filter(
(emoji) => isUnicodeEmoji(emoji) && parseFloat(emoji.v) === 11,
)
newEmojiSet.push({
title: value.title,
data: newData,
})
}

const customCategoryIndex = emojisByCategory.findIndex(({ title }) => title === 'custom')
newEmojiSet[customCategoryIndex]!.data = [
{
uri: Image.resolveAssetSource(require('example/assets/custom/shhhh.webp')).uri,
keywords: ['shhhh', 'face'],
name: 'shhhh',
},
{
uri: Image.resolveAssetSource(require('example/assets/custom/silly.webp')).uri,
keywords: ['silly', 'face'],
name: 'silly',
},
{
uri: Image.resolveAssetSource(require('example/assets/custom/woah.webp')).uri,
keywords: ['woaah', 'face'],
name: 'woaah',
},
]
return newEmojiSet
}

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

const handlePick = (emoji: EmojiType) => {
console.log(emoji)
setResult(emoji.emoji)
setResult(emoji)
setIsModalOpen((prev) => !prev)
}
return (
<>
<Results label={result} />
{result && <Result emoji={result} />}
<Button onPress={() => setIsModalOpen(true)} label="Open" />

<EmojiPicker
Expand Down
8 changes: 4 additions & 4 deletions example/app/(examples)/enable-recently.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { Button } from 'example/src/components/Button'
import { Results } from 'example/src/components/Results'
import React from 'react'
import EmojiPicker, { type EmojiType } from 'rn-emoji-keyboard'
import { Result } from 'example/src/components/Result'

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

const handlePick = (emoji: EmojiType) => {
console.log(emoji)
setResult(emoji.emoji)
setResult(emoji)
setIsModalOpen((prev) => !prev)
}
return (
<>
<Results label={result} />
{result && <Result emoji={result} />}
<Button onPress={() => setIsModalOpen(true)} label="Open" />

<EmojiPicker
Expand Down
8 changes: 4 additions & 4 deletions example/app/(examples)/search.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { Button } from 'example/src/components/Button'
import { Results } from 'example/src/components/Results'
import { Result } from 'example/src/components/Result'
import React from 'react'
import EmojiPicker, { type EmojiType } from 'rn-emoji-keyboard'

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

const handlePick = (emoji: EmojiType) => {
console.log(emoji)
setResult(emoji.emoji)
setResult(emoji)
setIsModalOpen((prev) => !prev)
}
return (
<>
<Results label={result} />
{result && <Result emoji={result} />}
<Button onPress={() => setIsModalOpen(true)} label="Open" />

<EmojiPicker
Expand Down
Loading

0 comments on commit e4116d5

Please sign in to comment.