lexical: render native emojis as Twemoji

environments/review-emoji-node-jkqetp/deployments/4054
Alex Gleason 1 year ago
parent 2a9cb08d08
commit 4b5602a086
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7

@ -1,7 +1,8 @@
import { $applyNodeReplacement, DecoratorNode } from 'lexical'; import { $applyNodeReplacement, DecoratorNode } from 'lexical';
import React from 'react'; import React from 'react';
import { Emoji } from 'soapbox/components/ui'; import { Emoji as Component } from 'soapbox/components/ui';
import { isNativeEmoji, type Emoji } from 'soapbox/features/emoji';
import type { import type {
DOMExportOutput, DOMExportOutput,
@ -13,29 +14,26 @@ import type {
} from 'lexical'; } from 'lexical';
type SerializedEmojiNode = Spread<{ type SerializedEmojiNode = Spread<{
name: string data: Emoji
src: string
type: 'emoji' type: 'emoji'
version: 1 version: 1
}, SerializedLexicalNode>; }, SerializedLexicalNode>;
class EmojiNode extends DecoratorNode<JSX.Element> { class EmojiNode extends DecoratorNode<JSX.Element> {
__name: string; __emoji: Emoji;
__src: string;
static getType(): 'emoji' { static getType(): 'emoji' {
return 'emoji'; return 'emoji';
} }
static clone(node: EmojiNode): EmojiNode { static clone(node: EmojiNode): EmojiNode {
return new EmojiNode(node.__name, node.__src, node.__key); return new EmojiNode(node.__emoji, node.__key);
} }
constructor(name: string, src: string, key?: NodeKey) { constructor(emoji: Emoji, key?: NodeKey) {
super(key); super(key);
this.__name = name; this.__emoji = emoji;
this.__src = src;
} }
createDOM(config: EditorConfig): HTMLElement { createDOM(config: EditorConfig): HTMLElement {
@ -60,16 +58,13 @@ class EmojiNode extends DecoratorNode<JSX.Element> {
return { element }; return { element };
} }
static importJSON(serializedNode: SerializedEmojiNode): EmojiNode { static importJSON({ data }: SerializedEmojiNode): EmojiNode {
const { name, src } = serializedNode; return $createEmojiNode(data);
const node = $createEmojiNode(name, src);
return node;
} }
exportJSON(): SerializedEmojiNode { exportJSON(): SerializedEmojiNode {
return { return {
name: this.__name, data: this.__emoji,
src: this.__src,
type: 'emoji', type: 'emoji',
version: 1, version: 1,
}; };
@ -88,15 +83,19 @@ class EmojiNode extends DecoratorNode<JSX.Element> {
} }
decorate(): JSX.Element { decorate(): JSX.Element {
return ( const emoji = this.__emoji;
<Emoji src={this.__src} alt={this.__name} className='emojione h-4 w-4' />
); if (isNativeEmoji(emoji)) {
return <Component emoji={emoji.native} alt={emoji.colons} className='emojione h-4 w-4' />;
} else {
return <Component src={emoji.imageUrl} alt={emoji.colons} className='emojione h-4 w-4' />;
}
} }
} }
function $createEmojiNode (name = '', src: string): EmojiNode { function $createEmojiNode(emoji: Emoji): EmojiNode {
const node = new EmojiNode(name, src); const node = new EmojiNode(emoji);
return $applyNodeReplacement(node); return $applyNodeReplacement(node);
} }

@ -33,9 +33,8 @@ import React, {
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import { clearComposeSuggestions, fetchComposeSuggestions } from 'soapbox/actions/compose'; import { clearComposeSuggestions, fetchComposeSuggestions } from 'soapbox/actions/compose';
import { useEmoji } from 'soapbox/actions/emojis'; import { useEmoji as chooseEmoji } from 'soapbox/actions/emojis';
import AutosuggestEmoji from 'soapbox/components/autosuggest-emoji'; import AutosuggestEmoji from 'soapbox/components/autosuggest-emoji';
import { isNativeEmoji } from 'soapbox/features/emoji';
import { useAppDispatch, useCompose } from 'soapbox/hooks'; import { useAppDispatch, useCompose } from 'soapbox/hooks';
import { selectAccount } from 'soapbox/selectors'; import { selectAccount } from 'soapbox/selectors';
import { textAtCursorMatchesToken } from 'soapbox/utils/suggestions'; import { textAtCursorMatchesToken } from 'soapbox/utils/suggestions';
@ -322,13 +321,8 @@ const AutosuggestPlugin = ({
if (typeof suggestion === 'object') { if (typeof suggestion === 'object') {
if (!suggestion.id) return; if (!suggestion.id) return;
dispatch(useEmoji(suggestion)); // eslint-disable-line react-hooks/rules-of-hooks dispatch(chooseEmoji(suggestion));
replaceMatch($createEmojiNode(suggestion));
if (isNativeEmoji(suggestion)) {
node.spliceText(offset, matchingString.length, `${suggestion.native} `, true);
} else {
replaceMatch($createEmojiNode(suggestion.colons, suggestion.imageUrl));
}
} else if (suggestion[0] === '#') { } else if (suggestion[0] === '#') {
node.setTextContent(`${suggestion} `); node.setTextContent(`${suggestion} `);
node.select(); node.select();

Loading…
Cancel
Save