2024-02-24 19:26:14 +00:00
|
|
|
import type { ExtendedRegExpMatchArray } from '@tiptap/core'
|
2022-12-27 18:38:57 +00:00
|
|
|
import {
|
|
|
|
Node,
|
|
|
|
mergeAttributes,
|
|
|
|
nodeInputRule,
|
2023-01-05 08:50:11 +00:00
|
|
|
nodePasteRule,
|
2022-12-27 18:38:57 +00:00
|
|
|
} from '@tiptap/core'
|
2023-01-02 04:53:53 +00:00
|
|
|
import { emojiRegEx, getEmojiAttributes } from '~/config/emojis'
|
2022-12-27 18:38:57 +00:00
|
|
|
|
2024-02-24 19:26:14 +00:00
|
|
|
function wrapHandler<T extends (...args: any[]) => any>(handler: T): T {
|
|
|
|
return <T>((...args: any[]) => {
|
|
|
|
try {
|
|
|
|
return handler(...args)
|
|
|
|
}
|
|
|
|
catch (e) {
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-03-30 19:01:24 +00:00
|
|
|
function createEmojiRule<NR extends typeof nodeInputRule | typeof nodePasteRule>(nodeRule: NR,
|
|
|
|
type: Parameters<NR>[0]['type']): ReturnType<NR>[] {
|
2023-01-05 08:50:11 +00:00
|
|
|
const rule = nodeRule({
|
|
|
|
find: emojiRegEx as RegExp,
|
|
|
|
type,
|
2024-02-24 19:26:14 +00:00
|
|
|
getAttributes: (match: ExtendedRegExpMatchArray) => {
|
2023-01-05 08:50:11 +00:00
|
|
|
const [native] = match
|
|
|
|
return getEmojiAttributes(native)
|
|
|
|
},
|
|
|
|
}) as ReturnType<NR>
|
|
|
|
|
|
|
|
// Error catch for unsupported emoji
|
2024-02-24 19:26:14 +00:00
|
|
|
rule.handler = wrapHandler(rule.handler.bind(rule))
|
2023-01-05 08:50:11 +00:00
|
|
|
|
2024-02-24 19:26:14 +00:00
|
|
|
return [rule]
|
2023-01-05 08:50:11 +00:00
|
|
|
}
|
|
|
|
|
2023-01-16 11:40:47 +00:00
|
|
|
export const TiptapPluginEmoji = Node.create({
|
2022-12-27 19:13:50 +00:00
|
|
|
name: 'em-emoji',
|
2022-12-27 18:38:57 +00:00
|
|
|
|
2022-12-27 19:13:50 +00:00
|
|
|
inline: () => true,
|
|
|
|
group: () => 'inline',
|
|
|
|
draggable: false,
|
2022-12-27 18:38:57 +00:00
|
|
|
|
2022-12-27 19:13:50 +00:00
|
|
|
parseHTML() {
|
|
|
|
return [
|
|
|
|
{
|
2023-01-02 04:53:53 +00:00
|
|
|
tag: 'img.iconify-emoji',
|
2022-12-27 19:13:50 +00:00
|
|
|
},
|
|
|
|
]
|
2022-12-27 18:38:57 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
addAttributes() {
|
|
|
|
return {
|
2023-01-02 04:53:53 +00:00
|
|
|
alt: {
|
2022-12-27 18:38:57 +00:00
|
|
|
default: null,
|
|
|
|
},
|
2023-01-02 04:53:53 +00:00
|
|
|
src: {
|
|
|
|
default: null,
|
|
|
|
},
|
|
|
|
class: {
|
2022-12-27 20:42:58 +00:00
|
|
|
default: null,
|
|
|
|
},
|
2022-12-27 18:38:57 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2022-12-27 19:13:50 +00:00
|
|
|
renderHTML(args) {
|
2023-01-02 04:53:53 +00:00
|
|
|
return ['img', mergeAttributes(this.options.HTMLAttributes, args.HTMLAttributes)]
|
2022-12-27 18:38:57 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
addCommands() {
|
|
|
|
return {
|
2023-01-02 04:53:53 +00:00
|
|
|
insertEmoji: code => ({ commands }) => {
|
2022-12-27 18:38:57 +00:00
|
|
|
return commands.insertContent({
|
|
|
|
type: this.name,
|
2023-01-02 04:53:53 +00:00
|
|
|
attrs: getEmojiAttributes(code),
|
2022-12-27 18:38:57 +00:00
|
|
|
})
|
|
|
|
},
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
addInputRules() {
|
2023-01-05 08:50:11 +00:00
|
|
|
return createEmojiRule(nodeInputRule, this.type)
|
|
|
|
},
|
|
|
|
|
|
|
|
addPasteRules() {
|
|
|
|
return createEmojiRule(nodePasteRule, this.type)
|
2022-12-27 18:38:57 +00:00
|
|
|
},
|
|
|
|
})
|