Skip to content

Commit

Permalink
feat(core): add popularEmoji to BaseMoji
Browse files Browse the repository at this point in the history
  • Loading branch information
ifiokjr committed Feb 15, 2021
1 parent edd4a29 commit 7c81be1
Show file tree
Hide file tree
Showing 3 changed files with 174 additions and 19 deletions.
5 changes: 5 additions & 0 deletions .changeset/bright-dots-drop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@svgmoji/core': minor
---

Add `popularEmoji` to the `BaseMoji` abstract class. Now when the provided query is absent in `Moji#search` the `popularEmoji` are returned. This can also be set in the constructor with an array of unicode / hexcode representations of the emoji. The default values are taken from the top **100** frequently used emoji as listed [here](https://home.unicode.org/emoji/emoji-frequency/).
5 changes: 2 additions & 3 deletions packages/svgmoji__core/__tests__/base-moji.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,7 @@ describe('search', () => {
expect(values.some((emoji) => emoji.hexcode === '261D-1F3FF')).toBe(false);
});

it('bypasses searching when no query is empty', () => {
expect(moji.search('')).toBe(moji.data);
expect(moji.search('', { excludeTone: true })).toBe(moji.tonelessData);
it('bypasses searching when query is empty', () => {
expect(moji.search('')[0]).toEqual(moji.popularEmoji[0]);
});
});
183 changes: 167 additions & 16 deletions packages/svgmoji__core/src/base-moji.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ interface MojiProps {
* @default `1F44D` // 👍
*/
fallback?: string;

/**
* A list of the popular emoji that should be used when the query is empty.
*
* The string can be the hexcode or the native emoji unicode.
*
* @default `POPULAR_EMOJI`
*/
popular?: string[];
}

export abstract class Moji {
Expand Down Expand Up @@ -61,6 +70,11 @@ export abstract class Moji {
*/
fallback: FlatEmoji;

/**
* A list of popular emoji that can be presented when an empty string is provided as the query.
*/
popularEmoji: FlatEmoji[];

/**
* Cache the results for finding an emoji.
*/
Expand All @@ -78,10 +92,11 @@ export abstract class Moji {
* @param data - data which is used to lookup the groups and subgroups for the emoji instance
* @param fallback - the default hexcode to use when none can be found.
*/
constructor({ data, type, fallback = '1F44D' }: MojiProps) {
constructor({ data, type, fallback = '1F44D', popular = DEFAULT_POPULAR_EMOJI }: MojiProps) {
this.type = type;
this.data = isMinifiedEmojiList(data) ? populateMinifiedEmoji(data) : data;
this.tonelessData = this.data.filter((emoji) => !emoji.tone);
this.popularEmoji = this.populatePopularEmoji(popular);

const fallbackEmoji = this.find(fallback);

Expand Down Expand Up @@ -137,20 +152,7 @@ export abstract class Moji {
}

for (const emoji of this.data) {
if (
// This is a native emoji match
emoji.emoji === code ||
// This uses the underlying text representation of the emoji
emoji.text === code ||
// This is a hexcode match.
emoji.hexcode === code ||
// There is a match for the shortcode
emoji.shortcodes?.includes(code) ||
// There is a match for the shortcode, but with surrounding braces.
emoji.shortcodes?.map((shortcode) => `:${shortcode}:`).includes(code) ||
// The provided code matches the emoticon.
(emoji.emoticon && generateEmoticonPermutations(emoji.emoticon).includes(code))
) {
if (emojiMatchesCode(code, emoji)) {
this.#findCache.set(code, emoji);
return emoji;
}
Expand All @@ -170,7 +172,7 @@ export abstract class Moji {
const data = excludeTone ? this.tonelessData : this.data;

if (!query) {
return data;
return take(this.popularEmoji, maxResults);
}

return take(
Expand Down Expand Up @@ -205,6 +207,23 @@ export abstract class Moji {

return skins;
}

/**
* Populate the popular emoji codes.
*/
private populatePopularEmoji(codes: string[]): FlatEmoji[] {
const popularEmoji: FlatEmoji[] = [];

for (const code of codes) {
const emoji = this.find(code);

if (emoji) {
popularEmoji.push(emoji);
}
}

return popularEmoji;
}
}

const DEFAULT_OPTIONS: Required<BaseMojiProps> = {
Expand Down Expand Up @@ -243,3 +262,135 @@ function take<Type>(array: Type[], count: number): Type[] {
count = Math.max(Math.min(0, count), count === -1 ? array.length : count);
return array.slice(0, count);
}

/**
* Check if the emoji matches the provided code.
*/
function emojiMatchesCode(code: string, emoji: FlatEmoji): boolean {
if (
// This is a native emoji match
emoji.emoji === code ||
// This uses the underlying text representation of the emoji
emoji.text === code ||
// This is a hexcode match.
emoji.hexcode === code ||
// There is a match for the shortcode
emoji.shortcodes?.includes(code) ||
// There is a match for the shortcode, but with surrounding braces.
emoji.shortcodes?.map((shortcode) => `:${shortcode}:`).includes(code) ||
// The provided code matches the emoticon.
(emoji.emoticon && generateEmoticonPermutations(emoji.emoticon).includes(code))
) {
return true;
}

return false;
}

/**
* A list of some of the most popular emoji.
*
* Derived from https://home.unicode.org/emoji/emoji-frequency/
*/
export const DEFAULT_POPULAR_EMOJI = [
'😂',
'❤️',
'😍',
'🤣',
'😊',
'🙏',
'💕',
'😭',
'😘',
'👍',
'😅',
'👏',
'😁',
'🔥',
'💔',
'💖',
'😢',
'🤔',
'😆',
'🙄',
'💪',
'😉',
'☺️',
'👌',
'🤗',
'😔',
'😎',
'😇',
'🌹',
'🤦',
'🎉',
'💞',
'✌️',
'✨',
'🤷',
'😱',
'😌',
'🌸',
'🙌',
'😋',
'😏',
'🙂',
'🤩',
'😄',
'😀',
'😃',
'💯',
'🙈',
'👇',
'🎶',
'😒',
'🤭',
'❣️',
'❗',
'😜',
'💋',
'👀',
'😪',
'😑',
'💥',
'🙋',
'😞',
'😩',
'😡',
'🤪',
'👊',
'☀️',
'😥',
'🤤',
'👉',
'💃',
'😳',
'✋',
'😚',
'😝',
'😴',
'🌟',
'😬',
'🙃',
'🍀',
'🌷',
'😻',
'😓',
'⭐',
'✅',
'🌈',
'😈',
'🤘',
'💦',
'✔️',
'😣',
'🏃',
'💐',
'☹️',
'🎊',
'💘',
'😠',
'☝️',
'😕',
'🌺',
];

0 comments on commit 7c81be1

Please sign in to comment.