elk/composables/tiptap/custom-emoji.ts

117 lines
2.0 KiB
TypeScript

import {
Node,
mergeAttributes,
nodeInputRule,
} from '@tiptap/core'
export interface EmojiOptions {
inline: boolean
allowBase64: boolean
HTMLAttributes: Record<string, any>
}
declare module '@tiptap/core' {
interface Commands<ReturnType> {
emoji: {
/**
* Insert a custom emoji.
*/
insertCustomEmoji: (options: {
src: string
alt?: string
title?: string
}) => ReturnType
/**
* Insert a emoji.
*/
insertEmoji: (native: string) => ReturnType
}
}
}
const inputRegex = /(?:^|\s)(!\[(.+|:?)\]\((\S+)(?:\s+["'](\S+)["'])?\))$/
export const TiptapPluginCustomEmoji = Node.create<EmojiOptions>({
name: 'custom-emoji',
addOptions() {
return {
inline: false,
allowBase64: false,
HTMLAttributes: {},
}
},
inline() {
return this.options.inline
},
group() {
return this.options.inline ? 'inline' : 'block'
},
draggable: false,
addAttributes() {
return {
'src': {
default: null,
},
'alt': {
default: null,
},
'title': {
default: null,
},
'width': {
default: null,
},
'height': {
default: null,
},
'data-emoji-id': {
default: null,
},
}
},
parseHTML() {
return [
{
tag: this.options.allowBase64
? 'img[src]'
: 'img[src]:not([src^="data:"])',
},
]
},
renderHTML({ HTMLAttributes }) {
return ['img', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)]
},
addCommands() {
return {
insertCustomEmoji: options => ({ commands }) => {
return commands.insertContent({
type: this.name,
attrs: options,
})
},
}
},
addInputRules() {
return [
nodeInputRule({
find: inputRegex,
type: this.type,
getAttributes: (match) => {
const [,, alt, src, title] = match
return { src, alt, title }
},
}),
]
},
})