Browse Source

Support custom emoji data

master
Joe Attardi 3 years ago
parent
commit
788f8abe65
  1. 62
      src/emojiArea.test.ts
  2. 34
      src/emojiArea.ts
  3. 19
      src/index.ts
  4. 2
      src/types.ts
  5. 22
      src/util.ts

62
src/emojiArea.test.ts

@ -5,13 +5,22 @@ import emojiData from './data/emoji';
import { EmojiArea } from './emojiArea';
import { i18n } from './i18n';
import { buildEmojiCategoryData } from './util';
const emitter = new Emitter();
const emojiCategoryData = buildEmojiCategoryData(emojiData);
describe('EmojiArea', () => {
test('renders an emoji list for each category', () => {
const emojiArea = new EmojiArea(emitter, i18n, {
emojiVersion: '11.0'
}).render();
const emojiArea = new EmojiArea(
emitter,
i18n,
{
emojiVersion: '11.0'
},
emojiCategoryData
).render();
const containers = emojiArea.querySelectorAll('.emoji-picker__container');
expect(containers).toHaveLength(emojiData.categories.length);
@ -26,10 +35,15 @@ describe('EmojiArea', () => {
});
test('only renders emoji lists for specified categories', () => {
const emojiArea = new EmojiArea(emitter, i18n, {
emojiVersion: '11.0',
categories: ['smileys', 'animals']
}).render();
const emojiArea = new EmojiArea(
emitter,
i18n,
{
emojiVersion: '11.0',
categories: ['smileys', 'animals']
},
emojiCategoryData
).render();
const containers = emojiArea.querySelectorAll('.emoji-picker__container');
expect(containers).toHaveLength(2);
@ -45,11 +59,16 @@ describe('EmojiArea', () => {
});
test('includes the recents category if showRecents is true', () => {
const emojiArea = new EmojiArea(emitter, i18n, {
emojiVersion: '11.0',
categories: ['smileys', 'animals'],
showRecents: true
}).render();
const emojiArea = new EmojiArea(
emitter,
i18n,
{
emojiVersion: '11.0',
categories: ['smileys', 'animals'],
showRecents: true
},
emojiCategoryData
).render();
const containers = emojiArea.querySelectorAll('.emoji-picker__container');
expect(containers).toHaveLength(3);
@ -66,13 +85,18 @@ describe('EmojiArea', () => {
});
test('selects the initial category', () => {
const emojiArea = new EmojiArea(emitter, i18n, {
emojiVersion: '11.0',
categories: ['smileys', 'animals'],
showRecents: true,
initialCategory: 'animals',
showCategoryButtons: true
});
const emojiArea = new EmojiArea(
emitter,
i18n,
{
emojiVersion: '11.0',
categories: ['smileys', 'animals'],
showRecents: true,
initialCategory: 'animals',
showCategoryButtons: true
},
emojiCategoryData
);
const container = emojiArea.render();
emojiArea.reset();

34
src/emojiArea.ts

@ -24,15 +24,15 @@ import {
import { createElement } from './util';
import { load } from './recent';
const emojiCategories: { [key: string]: EmojiRecord[] } = {};
emojiData.emoji.forEach(emoji => {
let categoryList = emojiCategories[emojiData.categories[emoji.category]];
if (!categoryList) {
categoryList = emojiCategories[emojiData.categories[emoji.category]] = [];
}
// const emojiCategories: { [key: string]: EmojiRecord[] } = {};
// emojiData.emoji.forEach(emoji => {
// let categoryList = emojiCategories[emojiData.categories[emoji.category]];
// if (!categoryList) {
// categoryList = emojiCategories[emojiData.categories[emoji.category]] = [];
// }
categoryList.push(emoji);
});
// categoryList.push(emoji);
// });
export class EmojiArea {
private headerOffsets: number[];
@ -50,10 +50,14 @@ export class EmojiArea {
constructor(
private events: Emitter,
private i18n: I18NStrings,
private options: EmojiButtonOptions
private options: EmojiButtonOptions,
private emojiCategories: { [key: string]: EmojiRecord[] }
) {
this.emojisPerRow = options.emojisPerRow || 8;
this.categories = options.categories || options.emojiData?.categories || emojiData.categories;
this.categories =
options.emojiData?.categories ||
options.categories ||
emojiData.categories;
if (options.showRecents) {
this.categories = ['recents', ...this.categories];
@ -66,14 +70,14 @@ export class EmojiArea {
updateRecents(): void {
if (this.options.showRecents) {
emojiCategories.recents = load();
this.emojiCategories.recents = load();
const recentsContainer = this.emojis.querySelector(
`.${CLASS_EMOJI_CONTAINER}`
) as HTMLElement;
if (recentsContainer && recentsContainer.parentNode) {
recentsContainer.parentNode.replaceChild(
new EmojiContainer(
emojiCategories.recents,
this.emojiCategories.recents,
true,
this.events,
this.options,
@ -100,18 +104,18 @@ export class EmojiArea {
this.emojis = createElement('div', CLASS_EMOJIS);
if (this.options.showRecents) {
emojiCategories.recents = load();
this.emojiCategories.recents = load();
}
if (this.options.custom) {
emojiCategories.custom = this.options.custom.map(custom => ({
this.emojiCategories.custom = this.options.custom.map(custom => ({
...custom,
custom: true
}));
}
this.categories.forEach(category =>
this.addCategory(category, emojiCategories[category])
this.addCategory(category, this.emojiCategories[category])
);
requestAnimationFrame(() => {

19
src/index.ts

@ -17,7 +17,7 @@ import {
import { lazyLoadEmoji } from './lazyLoad';
import { EmojiPreview } from './preview';
import { Search } from './search';
import { createElement, empty } from './util';
import { createElement, empty, buildEmojiCategoryData } from './util';
import { VariantPopup } from './variantPopup';
import { i18n } from './i18n';
@ -108,6 +108,8 @@ export class EmojiButton {
private theme: EmojiTheme;
private emojiCategories: { [key: string]: EmojiRecord[] };
constructor(options: EmojiButtonOptions = {}) {
this.pickerVisible = false;
@ -126,6 +128,10 @@ export class EmojiButton {
this.theme = this.options.theme || 'light';
this.emojiCategories = buildEmojiCategoryData(
this.options.emojiData || emojiData
);
this.buildPicker();
}
@ -302,9 +308,9 @@ export class EmojiButton {
this.events,
this.i18n,
this.options,
this.options.emojiData.emoji,
this.options.emojiData?.emoji || emojiData.emoji,
(this.options.categories || []).map(category =>
this.options.emojiData.categories.indexOf(category)
(this.options.emojiData || emojiData).categories.indexOf(category)
)
);
@ -373,7 +379,12 @@ export class EmojiButton {
this.pickerEl.appendChild(this.pickerContent);
this.emojiArea = new EmojiArea(this.events, this.i18n, this.options);
this.emojiArea = new EmojiArea(
this.events,
this.i18n,
this.options,
this.emojiCategories
);
this.pickerContent.appendChild(this.emojiArea.render());
this.events.on(SHOW_SEARCH_RESULTS, this.showSearchResults.bind(this));

2
src/types.ts

@ -14,7 +14,7 @@ export interface EmojiRecord {
export interface EmojiData {
categories: string[];
emojiData: EmojiRecord[];
emoji: EmojiRecord[];
}
export interface EmojiSelection {

22
src/util.ts

@ -1,3 +1,5 @@
import { EmojiData, EmojiRecord } from './types';
export function createElement(
tagName: string,
className?: string
@ -23,3 +25,23 @@ export function formatEmojiName(name: string): string {
return words.join(' ');
}
export function buildEmojiCategoryData(
emojiData: EmojiData
): { [key: string]: EmojiRecord[] } {
const emojiCategories = {};
emojiData.emoji.forEach(emoji => {
let categoryList =
emojiCategories[emojiData.categories[emoji.category || 0]];
if (!categoryList) {
categoryList = emojiCategories[
emojiData.categories[emoji.category || 0]
] = [];
}
categoryList.push(emoji);
});
return emojiCategories;
}

Loading…
Cancel
Save