- {Emoji({ key: emoji.id, emoji: emoji, ...emojiProps })}
+ {NimbleEmoji({ key: emoji.id, emoji: emoji, data: this.data, ...emojiProps })}
@@ -66,7 +69,7 @@ export default class Preview extends React.PureComponent {
{idleEmoji &&
idleEmoji.length &&
- Emoji({ emoji: idleEmoji, ...emojiProps })}
+ NimbleEmoji({ emoji: idleEmoji, data: this.data, ...emojiProps })}
@@ -84,15 +87,5 @@ export default class Preview extends React.PureComponent {
}
}
-Preview.propTypes = {
- showSkinTones: PropTypes.bool,
- title: PropTypes.string.isRequired,
- emoji: PropTypes.string.isRequired,
- emojiProps: PropTypes.object.isRequired,
- skinsProps: PropTypes.object.isRequired,
-}
-
-Preview.defaultProps = {
- showSkinTones: true,
- onChange: () => {},
-}
+NimblePreview.propTypes = { ...PreviewPropTypes, data: PropTypes.object.isRequired }
+NimblePreview.defaultProps = PreviewDefaultProps
diff --git a/src/components/search.js b/src/components/search.js
index 71e8dc4..f826acf 100644
--- a/src/components/search.js
+++ b/src/components/search.js
@@ -1,11 +1,14 @@
import React from 'react'
import PropTypes from 'prop-types'
-import emojiIndex from '../utils/emoji-index'
+import NimbleEmojiIndex from '../utils/emoji-index'
+import { SearchPropTypes, SearchDefaultProps } from '../utils/shared-props'
-export default class Search extends React.PureComponent {
+export default class NimbleSearch extends React.PureComponent {
constructor(props) {
super(props)
+ this.data = props.data
+ this.emojiIndex = new NimbleEmojiIndex(this.data)
this.setRef = this.setRef.bind(this)
this.handleChange = this.handleChange.bind(this)
}
@@ -14,7 +17,7 @@ export default class Search extends React.PureComponent {
var value = this.input.value
this.props.onSearch(
- emojiIndex.search(value, {
+ this.emojiIndex.search(value, {
emojisToShowFilter: this.props.emojisToShowFilter,
maxResults: this.props.maxResults,
include: this.props.include,
@@ -49,16 +52,5 @@ export default class Search extends React.PureComponent {
}
}
-Search.propTypes = {
- onSearch: PropTypes.func,
- maxResults: PropTypes.number,
- emojisToShowFilter: PropTypes.func,
- autoFocus: PropTypes.bool,
-}
-
-Search.defaultProps = {
- onSearch: () => {},
- maxResults: 75,
- emojisToShowFilter: null,
- autoFocus: false,
-}
+NimbleSearch.propTypes = { ...SearchPropTypes, data: PropTypes.object.isRequired }
+NimbleSearch.defaultProps = SearchDefaultProps
diff --git a/src/index.js b/src/index.js
index e831839..eeed8b4 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,4 +1,4 @@
-import emojiIndex from './utils/emoji-index'
+import emojiIndex from './utils/parent-emoji-index'
import store from './utils/store'
import frequently from './utils/frequently'
diff --git a/src/utils/emoji-index.js b/src/utils/emoji-index.js
index 950d15d..9a2eb2b 100644
--- a/src/utils/emoji-index.js
+++ b/src/utils/emoji-index.js
@@ -1,180 +1,187 @@
-import data from '../data'
import { getData, getSanitizedData, intersect } from '.'
-var originalPool = {}
-var index = {}
-var emojisList = {}
-var emoticonsList = {}
-var customEmojisList = []
+export default class NimbleEmojiIndex {
+ constructor(data) {
+ this.data = data || {}
+ this.originalPool = {}
+ this.index = {}
+ this.emojis = {}
+ this.emoticons = {}
+ this.customEmojisList = []
-for (let emoji in data.emojis) {
- let emojiData = data.emojis[emoji],
- { short_names, emoticons } = emojiData,
- id = short_names[0]
+ this.buildIndex()
+ }
- if (emoticons) {
- emoticons.forEach((emoticon) => {
- if (emoticonsList[emoticon]) {
- return
+ buildIndex() {
+ for (let emoji in this.data.emojis) {
+ let emojiData = this.data.emojis[emoji],
+ { short_names, emoticons } = emojiData,
+ id = short_names[0]
+
+ if (emoticons) {
+ emoticons.forEach((emoticon) => {
+ if (this.emoticons[emoticon]) {
+ return
+ }
+
+ this.emoticons[emoticon] = id
+ })
}
- emoticonsList[emoticon] = id
+ this.emojis[id] = getSanitizedData(id, null, null, this.data)
+ this.originalPool[id] = emojiData
+ }
+ }
+
+ clearCustomEmojis(pool) {
+ this.customEmojisList.forEach((emoji) => {
+ let emojiId = emoji.id || emoji.short_names[0]
+
+ delete pool[emojiId]
+ delete emojisList[emojiId]
})
}
- emojisList[id] = getSanitizedData(id)
- originalPool[id] = emojiData
-}
+ addCustomToPool(custom, pool) {
+ if (this.customEmojisList.length) this.clearCustomEmojis(pool)
-function clearCustomEmojis(pool) {
- customEmojisList.forEach((emoji) => {
- let emojiId = emoji.id || emoji.short_names[0]
+ custom.forEach((emoji) => {
+ let emojiId = emoji.id || emoji.short_names[0]
- delete pool[emojiId]
- delete emojisList[emojiId]
- })
-}
+ if (emojiId && !pool[emojiId]) {
+ pool[emojiId] = getData(emoji, null, null, this.data)
+ this.emojis[emojiId] = getSanitizedData(emoji, null, null, this.data)
+ }
+ })
+
+ this.customEmojisList = custom
+ this.index = {}
+ }
-function addCustomToPool(custom, pool) {
- if (customEmojisList.length) clearCustomEmojis(pool)
+ search(
+ value,
+ { emojisToShowFilter, maxResults, include, exclude, custom = [] } = {},
+ ) {
+ if (this.customEmojisList != custom) this.addCustomToPool(custom, this.originalPool)
- custom.forEach((emoji) => {
- let emojiId = emoji.id || emoji.short_names[0]
+ maxResults || (maxResults = 75)
+ include || (include = [])
+ exclude || (exclude = [])
- if (emojiId && !pool[emojiId]) {
- pool[emojiId] = getData(emoji)
- emojisList[emojiId] = getSanitizedData(emoji)
- }
- })
+ var results = null,
+ pool = this.originalPool
- customEmojisList = custom
- index = {}
-}
+ if (value.length) {
+ if (value == '-' || value == '-1') {
+ return [this.emojis['-1']]
+ }
-function search(
- value,
- { emojisToShowFilter, maxResults, include, exclude, custom = [] } = {},
-) {
- if (customEmojisList != custom) addCustomToPool(custom, originalPool)
+ var values = value.toLowerCase().split(/[\s|,|\-|_]+/),
+ allResults = []
- maxResults || (maxResults = 75)
- include || (include = [])
- exclude || (exclude = [])
+ if (values.length > 2) {
+ values = [values[0], values[1]]
+ }
- var results = null,
- pool = originalPool
+ if (include.length || exclude.length) {
+ pool = {}
- if (value.length) {
- if (value == '-' || value == '-1') {
- return [emojisList['-1']]
- }
+ this.data.categories.forEach((category) => {
+ let isIncluded =
+ include && include.length ? include.indexOf(category.id) > -1 : true
+ let isExcluded =
+ exclude && exclude.length ? exclude.indexOf(category.id) > -1 : false
+ if (!isIncluded || isExcluded) {
+ return
+ }
- var values = value.toLowerCase().split(/[\s|,|\-|_]+/),
- allResults = []
+ category.emojis.forEach(
+ (emojiId) => (pool[emojiId] = this.data.emojis[emojiId]),
+ )
+ })
- if (values.length > 2) {
- values = [values[0], values[1]]
- }
-
- if (include.length || exclude.length) {
- pool = {}
-
- data.categories.forEach((category) => {
- let isIncluded =
- include && include.length ? include.indexOf(category.id) > -1 : true
- let isExcluded =
- exclude && exclude.length ? exclude.indexOf(category.id) > -1 : false
- if (!isIncluded || isExcluded) {
- return
+ if (custom.length) {
+ let customIsIncluded =
+ include && include.length ? include.indexOf('custom') > -1 : true
+ let customIsExcluded =
+ exclude && exclude.length ? exclude.indexOf('custom') > -1 : false
+ if (customIsIncluded && !customIsExcluded) {
+ this.addCustomToPool(custom, pool)
+ }
}
+ }
- category.emojis.forEach(
- (emojiId) => (pool[emojiId] = data.emojis[emojiId]),
- )
- })
+ allResults = values
+ .map((value) => {
+ var aPool = pool,
+ aIndex = this.index,
+ length = 0
- if (custom.length) {
- let customIsIncluded =
- include && include.length ? include.indexOf('custom') > -1 : true
- let customIsExcluded =
- exclude && exclude.length ? exclude.indexOf('custom') > -1 : false
- if (customIsIncluded && !customIsExcluded) {
- addCustomToPool(custom, pool)
- }
+ for (let charIndex = 0; charIndex < value.length; charIndex++) {
+ const char = value[charIndex]
+ length++
+
+ aIndex[char] || (aIndex[char] = {})
+ aIndex = aIndex[char]
+
+ if (!aIndex.results) {
+ let scores = {}
+
+ aIndex.results = []
+ aIndex.pool = {}
+
+ for (let id in aPool) {
+ let emoji = aPool[id],
+ { search } = emoji,
+ sub = value.substr(0, length),
+ subIndex = search.indexOf(sub)
+
+ if (subIndex != -1) {
+ let score = subIndex + 1
+ if (sub == id) score = 0
+
+ aIndex.results.push(this.emojis[id])
+ aIndex.pool[id] = emoji
+
+ scores[id] = score
+ }
+ }
+
+ aIndex.results.sort((a, b) => {
+ var aScore = scores[a.id],
+ bScore = scores[b.id]
+
+ return aScore - bScore
+ })
+ }
+
+ aPool = aIndex.pool
+ }
+
+ return aIndex.results
+ })
+ .filter((a) => a)
+
+ if (allResults.length > 1) {
+ results = intersect.apply(null, allResults)
+ } else if (allResults.length) {
+ results = allResults[0]
+ } else {
+ results = []
}
}
- allResults = values
- .map((value) => {
- var aPool = pool,
- aIndex = index,
- length = 0
+ if (results) {
+ if (emojisToShowFilter) {
+ results = results.filter((result) => emojisToShowFilter(pool[result.id]))
+ }
- for (let charIndex = 0; charIndex < value.length; charIndex++) {
- const char = value[charIndex]
- length++
-
- aIndex[char] || (aIndex[char] = {})
- aIndex = aIndex[char]
-
- if (!aIndex.results) {
- let scores = {}
-
- aIndex.results = []
- aIndex.pool = {}
-
- for (let id in aPool) {
- let emoji = aPool[id],
- { search } = emoji,
- sub = value.substr(0, length),
- subIndex = search.indexOf(sub)
-
- if (subIndex != -1) {
- let score = subIndex + 1
- if (sub == id) score = 0
-
- aIndex.results.push(emojisList[id])
- aIndex.pool[id] = emoji
-
- scores[id] = score
- }
- }
-
- aIndex.results.sort((a, b) => {
- var aScore = scores[a.id],
- bScore = scores[b.id]
-
- return aScore - bScore
- })
- }
-
- aPool = aIndex.pool
- }
-
- return aIndex.results
- })
- .filter((a) => a)
-
- if (allResults.length > 1) {
- results = intersect.apply(null, allResults)
- } else if (allResults.length) {
- results = allResults[0]
- } else {
- results = []
+ if (results && results.length > maxResults) {
+ results = results.slice(0, maxResults)
+ }
}
+
+ return results
}
-
- if (results) {
- if (emojisToShowFilter) {
- results = results.filter((result) => emojisToShowFilter(pool[result.id]))
- }
-
- if (results && results.length > maxResults) {
- results = results.slice(0, maxResults)
- }
- }
-
- return results
}
-export default { search, emojis: emojisList, emoticons: emoticonsList }
diff --git a/src/utils/index.js b/src/utils/index.js
index 43bd6f2..a7f8694 100644
--- a/src/utils/index.js
+++ b/src/utils/index.js
@@ -1,5 +1,4 @@
import buildSearch from './build-search'
-import data from '../data'
import stringFromCodePoint from '../polyfills/stringFromCodePoint'
const _JSON = JSON
@@ -58,7 +57,7 @@ function getSanitizedData() {
return sanitize(getData(...arguments))
}
-function getData(emoji, skin, set) {
+function getData(emoji, skin, set, data) {
var emojiData = {}
if (typeof emoji == 'string') {
@@ -68,7 +67,7 @@ function getData(emoji, skin, set) {
emoji = matches[1]
if (matches[2]) {
- skin = parseInt(matches[2])
+ skin = parseInt(matches[2], 10)
}
}
diff --git a/src/utils/parent-emoji-index.js b/src/utils/parent-emoji-index.js
new file mode 100644
index 0000000..5a13836
--- /dev/null
+++ b/src/utils/parent-emoji-index.js
@@ -0,0 +1,12 @@
+import data from '../data'
+import NimbleEmojiIndex from './emoji-index'
+
+const emojiIndex = new NimbleEmojiIndex(data)
+const emojis = emojiIndex.emojis
+const emoticons = emojiIndex.emoticons
+
+function search() {
+ return emojiIndex.search(...arguments)
+}
+
+export default { search, emojis, emoticons }
diff --git a/src/utils/shared-props.js b/src/utils/shared-props.js
new file mode 100644
index 0000000..bb05b7f
--- /dev/null
+++ b/src/utils/shared-props.js
@@ -0,0 +1,153 @@
+import PropTypes from 'prop-types'
+
+const CategoryPropTypes = {
+ emojis: PropTypes.array,
+ hasStickyPosition: PropTypes.bool,
+ name: PropTypes.string.isRequired,
+ native: PropTypes.bool.isRequired,
+ perLine: PropTypes.number.isRequired,
+ emojiProps: PropTypes.object.isRequired,
+ recent: PropTypes.arrayOf(PropTypes.string),
+}
+
+const CategoryDefaultProps = {
+ emojis: [],
+ hasStickyPosition: true,
+}
+
+const EmojiPropTypes = {
+ data: PropTypes.object.isRequired,
+ onOver: PropTypes.func,
+ onLeave: PropTypes.func,
+ onClick: PropTypes.func,
+ fallback: PropTypes.func,
+ backgroundImageFn: PropTypes.func,
+ native: PropTypes.bool,
+ forceSize: PropTypes.bool,
+ tooltip: PropTypes.bool,
+ skin: PropTypes.oneOf([1, 2, 3, 4, 5, 6]),
+ sheetSize: PropTypes.oneOf([16, 20, 32, 64]),
+ set: PropTypes.oneOf([
+ 'apple',
+ 'google',
+ 'twitter',
+ 'emojione',
+ 'messenger',
+ 'facebook',
+ ]),
+ size: PropTypes.number.isRequired,
+ emoji: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired,
+}
+
+const EmojiDefaultProps = {
+ skin: 1,
+ set: 'apple',
+ sheetSize: 64,
+ native: false,
+ forceSize: false,
+ tooltip: false,
+ backgroundImageFn: (set, sheetSize) =>
+ `https://unpkg.com/emoji-datasource-${set}@${EMOJI_DATASOURCE_VERSION}/img/${set}/sheets-256/${sheetSize}.png`,
+ onOver: () => {},
+ onLeave: () => {},
+ onClick: () => {},
+}
+
+const PickerPropTypes = {
+ onClick: PropTypes.func,
+ onSkinChange: PropTypes.func,
+ perLine: PropTypes.number,
+ emojiSize: PropTypes.number,
+ i18n: PropTypes.object,
+ style: PropTypes.object,
+ title: PropTypes.string,
+ emoji: PropTypes.string,
+ color: PropTypes.string,
+ set: EmojiPropTypes.set,
+ skin: EmojiPropTypes.skin,
+ native: PropTypes.bool,
+ backgroundImageFn: EmojiPropTypes.backgroundImageFn,
+ sheetSize: EmojiPropTypes.sheetSize,
+ emojisToShowFilter: PropTypes.func,
+ showPreview: PropTypes.bool,
+ showSkinTones: PropTypes.bool,
+ emojiTooltip: EmojiPropTypes.tooltip,
+ include: PropTypes.arrayOf(PropTypes.string),
+ exclude: PropTypes.arrayOf(PropTypes.string),
+ recent: PropTypes.arrayOf(PropTypes.string),
+ autoFocus: PropTypes.bool,
+ custom: PropTypes.arrayOf(
+ PropTypes.shape({
+ name: PropTypes.string.isRequired,
+ short_names: PropTypes.arrayOf(PropTypes.string).isRequired,
+ emoticons: PropTypes.arrayOf(PropTypes.string),
+ keywords: PropTypes.arrayOf(PropTypes.string),
+ imageUrl: PropTypes.string.isRequired,
+ })
+ ),
+}
+
+const PickerDefaultProps = {
+ onClick: () => {},
+ onSkinChange: () => {},
+ emojiSize: 24,
+ perLine: 9,
+ i18n: {},
+ style: {},
+ title: 'Emoji Martâ„¢',
+ emoji: 'department_store',
+ color: '#ae65c5',
+ set: EmojiDefaultProps.set,
+ skin: null,
+ defaultSkin: EmojiDefaultProps.skin,
+ native: EmojiDefaultProps.native,
+ sheetSize: EmojiDefaultProps.sheetSize,
+ backgroundImageFn: EmojiDefaultProps.backgroundImageFn,
+ emojisToShowFilter: null,
+ showPreview: true,
+ showSkinTones: true,
+ emojiTooltip: EmojiDefaultProps.tooltip,
+ autoFocus: false,
+ custom: [],
+}
+
+const PreviewPropTypes = {
+ showSkinTones: PropTypes.bool,
+ title: PropTypes.string.isRequired,
+ emoji: PropTypes.string.isRequired,
+ emojiProps: PropTypes.object.isRequired,
+ skinsProps: PropTypes.object.isRequired,
+}
+
+const PreviewDefaultProps = {
+ showSkinTones: true,
+ onChange: () => {},
+}
+
+
+const SearchPropTypes = {
+ onSearch: PropTypes.func,
+ maxResults: PropTypes.number,
+ emojisToShowFilter: PropTypes.func,
+ autoFocus: PropTypes.bool,
+}
+
+const SearchDefaultProps = {
+ onSearch: () => {},
+ maxResults: 75,
+ emojisToShowFilter: null,
+ autoFocus: false,
+}
+
+export {
+ CategoryPropTypes,
+ CategoryDefaultProps,
+ EmojiPropTypes,
+ EmojiDefaultProps,
+ PickerPropTypes,
+ PickerDefaultProps,
+ PreviewPropTypes,
+ PreviewDefaultProps,
+ SearchPropTypes,
+ SearchDefaultProps,
+}