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 type { Plugin, Transformer } from "unified"
import type { 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 }
}
}
}