import { visit } from 'unist-util-visit' import { Plugin, Transformer } from 'unified' import { Literal, Parent } from 'unist' import type { ElementContent } from 'hast' import type { EmojiSet } from 'emoji-mart' import { emojiRegex } from './isStringWithOnlyOneEmoji' export const EMOJI_SET: EmojiSet = 'twitter' const extractText = ( string: string, start: number, end: number ): ElementContent => { return { type: 'text', value: string.slice(start, end) } } export const emojiPlugin: Plugin<[], Literal> = () => { const transformer: Transformer> = (tree) => { visit, string>( tree, 'text', (node, position, parent: Parent | null) => { if (typeof node.value !== 'string') { return } position = position ?? 0 const definition: ElementContent[] = [] let lastIndex = 0 const match = emojiRegex.exec(node.value) if (match != null) { const value = match[0] if (match.index !== lastIndex) { definition.push(extractText(node.value, lastIndex, match.index)) } definition.push({ type: 'element', tagName: 'emoji', properties: { value }, children: [] }) lastIndex = match.index + value.length if (lastIndex !== node.value.length) { definition.push( extractText(node.value, lastIndex, node.value.length) ) } if (parent != null) { const last = parent.children.slice(position + 1) parent.children = parent.children.slice(0, position) parent.children = parent.children.concat(definition) parent.children = parent.children.concat(last) } } } ) } return transformer } declare global { namespace JSX { interface IntrinsicElements { emoji: { value: string } } } }