signal-desktop/ts/quill/auto-substitute-ascii-emojis/index.tsx

96 lines
2.4 KiB
TypeScript

// Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type Quill from 'quill';
import Delta from 'quill-delta';
import _ from 'lodash';
import type { EmojiData } from '../../components/emoji/lib';
import {
convertShortName,
convertShortNameToData,
} from '../../components/emoji/lib';
type AutoSubstituteAsciiEmojisOptions = {
skinTone: number;
};
const emojiMap: Record<string, string> = {
':)': 'slightly_smiling_face',
':-)': 'slightly_smiling_face',
':(': 'slightly_frowning_face',
':-(': 'slightly_frowning_face',
':D': 'smiley',
':-D': 'smiley',
':*': 'kissing',
':-*': 'kissing',
':P': 'stuck_out_tongue',
':-P': 'stuck_out_tongue',
';P': 'stuck_out_tongue_winking_eye',
';-P': 'stuck_out_tongue_winking_eye',
'D:': 'anguished',
"D-':": 'anguished',
':O': 'open_mouth',
':-O': 'open_mouth',
":'(": 'cry',
":'-(": 'cry',
':/': 'confused',
':-/': 'confused',
';)': 'wink',
';-)': 'wink',
'(Y)': '+1',
'(N)': '-1',
};
export class AutoSubstituteAsciiEmojis {
options: AutoSubstituteAsciiEmojisOptions;
quill: Quill;
constructor(quill: Quill, options: AutoSubstituteAsciiEmojisOptions) {
this.options = options;
this.quill = quill;
this.quill.on(
'text-change',
_.debounce(() => this.onTextChange(), 100)
);
}
onTextChange(): void {
const range = this.quill.getSelection();
if (!range) {
return;
}
const [blot, index] = this.quill.getLeaf(range.index);
if (blot !== undefined && blot.text !== undefined) {
const blotText: string = blot.text;
Object.entries(emojiMap).some(([textEmoji, emojiName]) => {
if (blotText.substring(0, index).endsWith(textEmoji)) {
const emojiData = convertShortNameToData(
emojiName,
this.options.skinTone
);
if (emojiData) {
this.insertEmoji(
emojiData,
range.index - textEmoji.length,
textEmoji.length
);
return true;
}
}
return false;
});
}
}
insertEmoji(emojiData: EmojiData, index: number, range: number): void {
const emoji = convertShortName(emojiData.short_name, this.options.skinTone);
const delta = new Delta().retain(index).delete(range).insert({ emoji });
this.quill.updateContents(delta, 'user');
this.quill.setSelection(index + 1, 0);
}
}