OverviewFilesCommitsIssuesDocsReleasesPeers

keet-deobfuscated / @holepunchto / keet-editor / src / extensions / emojis-fixer.js

79 lines · javascript ref:
import { Extension as e } from "@tiptap/core"
import { Plugin as t, PluginKey as o } from "@tiptap/pm/state"
const n = "️",
  r = "‍",
  s = /[\u{1F3FB}-\u{1F3FF}]/u,
  i = "emojisFixer",
  m = /\p{Extended_Pictographic}/u
export function normalizeEmoji(e) {
  if (!m.test(e)) return e
  const t = Array.from(e)
  let o = !1
  for (let e = 0; e < t.length; e += 1) {
    const i = t[e]
    if (!(m.test(i) && 1 === i.length && i.codePointAt(0) < 65535)) continue
    const a = t[e + 1]
    t[e - 1] === r || a === r || s.test(a) || (a !== n && ((t[e] = i + n), (o = !0)))
  }
  return o ? t.join("") : e
}
export const segmenter =
  "undefined" != typeof Intl && Intl.Segmenter
    ? new Intl.Segmenter(void 0, { granularity: "grapheme" })
    : null
export function splitIntoEmojiNodes(e, t, o, n) {
  const r = o.nodes.emoji
  if (!r || !m.test(e)) return null
  const s = segmenter ? [...segmenter.segment(e)].map((e) => e.segment) : Array.from(e),
    i = []
  let a = ""
  for (const e of s)
    if (m.test(e)) {
      a && (i.push(o.text(a, t)), (a = ""))
      const s = normalizeEmoji(e)
      if (n) {
        const e = n.getEmojiData(s) || n.getEmojiData(s + "️"),
          t = e?.shortCodes?.[0] || ""
        i.push(r.create({ "data-emoji": s, "data-shortcode": t }, o.text(s)))
      } else a += s
    } else a += e
  return (a && i.push(o.text(a, t)), i.length ? i : null)
}
export const EmojisFixer = e.create({
  name: "emojisFixer",
  addOptions: () => ({ emojiModule: null }),
  addProseMirrorPlugins() {
    const { emojiModule: e } = this.options
    return [
      new t({
        key: new o("emojisFixer"),
        appendTransaction(t, o, n) {
          if (t.some((e) => e.getMeta(i))) return null
          const { schema: r } = n,
            s = r.nodes.emoji,
            a = []
          if (
            (n.doc.descendants((t, o, n) => {
              if (!t.isText) return
              if (n?.type === s) return
              const i = t.text
              if (s && m.test(i)) {
                const n = splitIntoEmojiNodes(i, t.marks, r, e)
                n && a.push({ from: o, to: o + t.nodeSize, nodes: n })
              } else {
                const e = normalizeEmoji(i)
                e !== i && a.push({ from: o, to: o + t.nodeSize, nodes: [r.text(e, t.marks)] })
              }
            }),
            0 === a.length)
          )
            return null
          let l = n.tr
          for (const { from: e, to: t, nodes: o } of a.reverse()) l = l.replaceWith(e, t, o)
          return l.setMeta(i, !0)
        },
      }),
    ]
  },
})