From 357c9cb92f60917572ea76c63eb779e736b804aa Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Thu, 26 Dec 2024 18:11:38 +0100 Subject: [PATCH] feat: :sparkles: Add inline emoji support to composer --- components/editor/content.vue | 2 + components/editor/emoji.ts | 80 +++++++++++++++++++++++++++++++++++ components/editor/emoji.vue | 16 +++++++ 3 files changed, 98 insertions(+) create mode 100644 components/editor/emoji.ts create mode 100644 components/editor/emoji.vue diff --git a/components/editor/content.vue b/components/editor/content.vue index 674298e..7bd03ff 100644 --- a/components/editor/content.vue +++ b/components/editor/content.vue @@ -13,6 +13,7 @@ import Superscript from "@tiptap/extension-superscript"; import Underline from "@tiptap/extension-underline"; import StarterKit from "@tiptap/starter-kit"; import { Editor, EditorContent } from "@tiptap/vue-3"; +import { Emoji } from "./emoji.ts"; import suggestion from "./suggestion.ts"; const content = defineModel("content"); @@ -43,6 +44,7 @@ const editor = new Editor({ }, suggestion, }), + Emoji, ], content: content.value, onUpdate: ({ editor }) => { diff --git a/components/editor/emoji.ts b/components/editor/emoji.ts new file mode 100644 index 0000000..6a0ae46 --- /dev/null +++ b/components/editor/emoji.ts @@ -0,0 +1,80 @@ +/** + * Adapted from https://github.com/ueberdosis/tiptap/blob/main/packages/extension-image/src/image.ts + */ + +import { Node, nodeInputRule } from "@tiptap/core"; +import { VueNodeViewRenderer } from "@tiptap/vue-3"; +import EmojiVue from "./emoji.vue"; + +export interface EmojiOptions { + /** + * Shortcode of the emoji. + */ + shortcode: string; +} + +declare module "@tiptap/core" { + interface Commands { + emoji: { + /** + * Add an emoji + * @param options The image attributes + * @example + * editor + * .commands + * .setEmoji({ shortcode: 'smile' }) + */ + setImage: (options: { + shortcode: string; + }) => ReturnType; + }; + } +} + +/** + * Matches an emoji to a :shortcode: on input. + */ +export const inputRegex = /(?:^|\s)(:([a-zA-Z0-9_]+):)$/; + +/** + * This extension allows you to insert emojis. + */ +export const Emoji = Node.create({ + name: "emoji", + + draggable: true, + + group: "inline", + + inline: true, + + addAttributes() { + return { + shortcode: { + default: this.options.shortcode, + }, + }; + }, + + renderHTML({ node }) { + return `:${node.attrs.shortcode}:`; + }, + + addNodeView() { + return VueNodeViewRenderer(EmojiVue); + }, + + addInputRules() { + return [ + nodeInputRule({ + find: inputRegex, + type: this.type, + getAttributes: (match) => { + const [, , shortcode] = match; + + return { shortcode }; + }, + }), + ]; + }, +}); diff --git a/components/editor/emoji.vue b/components/editor/emoji.vue new file mode 100644 index 0000000..0c293df --- /dev/null +++ b/components/editor/emoji.vue @@ -0,0 +1,16 @@ + + +