2
2
mirror of https://github.com/Thream/website.git synced 2024-07-21 09:28:32 +02:00
website/components/Emoji/emojiPlugin.ts

72 lines
2.0 KiB
TypeScript

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<string>> = () => {
const transformer: Transformer<Literal<string>> = (tree) => {
visit<Literal<string>, string>(
tree,
'text',
(node, position, parent: Parent<ElementContent> | 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 }
}
}
}