OverviewFilesCommitsIssuesDocsReleasesPeers

keet-deobfuscated / @holepunchto / keet-editor / src / extensions / mention.js

106 lines · javascript ref:
import { mergeAttributes as t } from "@tiptap/core"
import { Mention as e } from "@tiptap/extension-mention"
import { Plugin as n, PluginKey as s } from "prosemirror-state"
export function mentionPastePlugin(t) {
  const { suggestion: e, idKey: r = "memberId", labelKey: o = "displayName" } = t,
    i = new Map(),
    a = e.items
  let u = null
  return new n({
    key: new s("mentionPaste"),
    view: (t) => (
      (u = t),
      {
        destroy() {
          u = null
        },
      }
    ),
    appendTransaction(t, e, n) {
      const s = t.some((t) => t.getMeta("paste"))
      if (!s) return null
      const l = n.tr
      let c = !1
      const d = []
      return (
        n.doc.descendants((t, e) => {
          if (!t.isText) return
          const s = async (e, n, s) => {
              let r = i.get(e)
              return (
                r ||
                  ((r = (await a({ query: e })) || []),
                  (r = r
                    .map((t) => ({ ...t, mention: `@${t[o]}` }))
                    .sort((t, e) => e[o].length - t[o].length)),
                  i.set(e, r)),
                r.find((e) => t.text.slice(n, s) === e.mention)
              )
            },
            u = [...t.text.matchAll(/@[\w]+/g)]
          if (u.length)
            for (const t of u) {
              const i = t[0],
                a = t.index ?? 0,
                u = a + i.length,
                m = i.slice(1)
              d.push(
                (async () => {
                  const t = await s(m, a, u)
                  if (!t) return
                  const i = e + a,
                    d = e + u,
                    p = n.schema.nodes.mention.create({ id: t[r], label: t[o] })
                  ;(l.replaceWith(i, d, p), (c = !0))
                })(),
              )
            }
        }),
        d.length &&
          Promise.all(d)
            .then(() => {
              ;(c && u && u.dispatch(l), i.clear())
            })
            .catch(console.error),
        null
      )
    },
  })
}
export const Mention = e.extend({
  addOptions() {
    const e = this.parent?.()
    return {
      ...e,
      renderHTML({ options: e, node: n }) {
        const s = n.attrs.id === e.myMentionId
        return [
          "span",
          {
            ...t(this.HTMLAttributes, e.HTMLAttributes),
            class: "mention " + (s ? "mention-me" : ""),
          },
          `${e.suggestion.char || ""}${n.attrs.label ?? n.attrs.id}`,
        ]
      },
      suggestion: {
        ...e?.suggestion,
        startOfLine: !1,
        allowedPrefixes: [
          " ",
          "\\u2E80-\\u2EFF\\u2F00-\\u2FDF\\u3040-\\u30FF\\u31F0-\\u31FF\\u3400-\\u4DBF\\u4E00-\\u9FFF\\uF900-\\uFAFF\\uAC00-\\uD7AF\\u1100-\\u11FF\\u3130-\\u318F",
        ],
      },
      myMentionId: null,
    }
  },
  addStorage: () => ({ suggestionOpen: !1 }),
  addAttributes() {
    return { ...this.parent?.(), class: { default: "mention" } }
  },
  renderLabel: ({ options: t, node: e }) => `${t.suggestion.char}${e.attrs.label ?? e.attrs.id}`,
  addProseMirrorPlugins() {
    return [...(this.parent?.() || []), mentionPastePlugin(this.options)]
  },
})