Files
voidraft/frontend/src/views/editor/extensions/markdown/plugins/emoji.ts

58 lines
1.4 KiB
TypeScript

/**
* Emoji handler and theme.
*/
import { Decoration, EditorView, WidgetType } from '@codemirror/view';
import { RangeTuple } from '../util';
import { SyntaxNode } from '@lezer/common';
import { BuildContext } from './types';
import { emojies } from '@/common/constant/emojies';
class EmojiWidget extends WidgetType {
constructor(readonly emoji: string, readonly name: string) { super(); }
eq(other: EmojiWidget) { return other.emoji === this.emoji; }
toDOM(): HTMLElement {
const span = document.createElement('span');
span.className = 'cm-emoji';
span.textContent = this.emoji;
span.title = `:${this.name}:`;
return span;
}
}
/**
* Handle Emoji node (:emoji:).
*/
export function handleEmoji(
ctx: BuildContext,
nf: number,
nt: number,
node: SyntaxNode,
inCursor: boolean,
ranges: RangeTuple[]
): void {
if (ctx.seen.has(nf)) return;
ctx.seen.add(nf);
ranges.push([nf, nt]);
if (inCursor) return;
const nameNode = node.getChild('EmojiName');
if (!nameNode) return;
const name = ctx.view.state.sliceDoc(nameNode.from, nameNode.to).toLowerCase();
const emojiChar = emojies[name];
if (emojiChar) {
ctx.items.push({ from: nf, to: nt, deco: Decoration.replace({ widget: new EmojiWidget(emojiChar, name) }) });
}
}
/**
* Theme for emoji.
*/
export const emojiTheme = EditorView.baseTheme({
'.cm-emoji': {
cursor: 'default',
fontSize: 'inherit',
lineHeight: 'inherit'
}
});