diff --git a/.changeset/thin-fans-drive.md b/.changeset/thin-fans-drive.md new file mode 100644 index 0000000..bd83a81 --- /dev/null +++ b/.changeset/thin-fans-drive.md @@ -0,0 +1,5 @@ +--- +"@bicou/directus-extension-tiptap": minor +--- + +emoji button and suggestions diff --git a/package.json b/package.json index 07d0571..1c78d1e 100644 --- a/package.json +++ b/package.json @@ -68,6 +68,7 @@ "@tiptap/extension-typography": "^2.1.13", "@tiptap/extension-underline": "^2.1.13", "@tiptap/pm": "^2.1.13", + "@tiptap/suggestion": "^2.1.13", "@tiptap/starter-kit": "^2.1.13" }, "devDependencies": { @@ -87,6 +88,7 @@ "rollup": "^4.8.0", "rollup-plugin-node-externals": "^6.1.2", "sass": "^1.69.5", + "tippy.js": "^6.3.7", "typescript": "~5.2.2", "vue": "^3.3.11", "vue-i18n": "^9.8.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 059a40b..1fc1f33 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -62,6 +62,9 @@ dependencies: '@tiptap/starter-kit': specifier: ^2.1.13 version: 2.1.13(@tiptap/pm@2.1.13) + '@tiptap/suggestion': + specifier: ^2.1.13 + version: 2.1.13(@tiptap/core@2.1.13)(@tiptap/pm@2.1.13) optionalDependencies: '@tiptap-pro/extension-emoji': @@ -120,6 +123,9 @@ devDependencies: sass: specifier: ^1.69.5 version: 1.69.5 + tippy.js: + specifier: ^6.3.7 + version: 6.3.7 typescript: specifier: ~5.2.2 version: 5.2.2 @@ -1581,7 +1587,6 @@ packages: '@tiptap/core': 2.1.13(@tiptap/pm@2.1.13) '@tiptap/pm': 2.1.13 dev: false - optional: true /@tiptap/vue-3@2.1.13(@tiptap/core@2.1.13)(@tiptap/pm@2.1.13)(vue@3.3.11): resolution: {integrity: sha512-sPMT+uXtPfYLQioXtxxMLij234++PEf5Z43/auOLu737pKdgBr7w0sC8oYiZMgFt9dNCZWBrvT0fupF8yQN8AQ==} diff --git a/src/components/emoji-list.vue b/src/components/emoji-list.vue new file mode 100644 index 0000000..95fce4b --- /dev/null +++ b/src/components/emoji-list.vue @@ -0,0 +1,113 @@ + + + + + diff --git a/src/extensions/emoji-suggestion.ts b/src/extensions/emoji-suggestion.ts new file mode 100644 index 0000000..aeb1dc6 --- /dev/null +++ b/src/extensions/emoji-suggestion.ts @@ -0,0 +1,66 @@ +import { VueRenderer } from "@tiptap/vue-3"; +import EmojiList from "../components/emoji-list.vue"; +import type { SuggestionOptions } from "@tiptap/suggestion"; +import type { EmojiItem } from "@tiptap-pro/extension-emoji"; +import tippy, { type Instance as TippyInstance } from "tippy.js"; + +export const suggestion: Omit = { + items: ({ editor, query }) => { + return editor.storage.emoji.emojis + .filter(({ shortcodes, tags }: EmojiItem) => { + return ( + shortcodes.find((shortcode) => shortcode.startsWith(query.toLowerCase())) || + tags.find((tag) => tag.startsWith(query.toLowerCase())) + ); + }) + .slice(0, 5); + }, + + render: () => { + let component: VueRenderer | null = null; + let popup: TippyInstance | null = null; + + return { + onStart: (props) => { + component = new VueRenderer(EmojiList, { + props, + editor: props.editor, + }); + + popup = tippy(document.body, { + getReferenceClientRect: props.clientRect, + appendTo: () => document.body, + content: component.element, + showOnCreate: true, + interactive: true, + trigger: "manual", + placement: "bottom-start", + }); + }, + + onUpdate(props) { + component?.updateProps(props); + + popup?.setProps({ + getReferenceClientRect: props.clientRect, + }); + }, + + onKeyDown(props) { + if (props.event.key === "Escape") { + popup?.hide(); + component?.destroy(); + + return true; + } + + return component?.ref?.onKeyDown(props); + }, + + onExit() { + popup?.destroy(); + component?.destroy(); + }, + }; + }, +}; diff --git a/src/extensions/emoji.ts b/src/extensions/emoji.ts index 5f2a4b9..3233a08 100644 --- a/src/extensions/emoji.ts +++ b/src/extensions/emoji.ts @@ -1,4 +1,5 @@ import type { ExtensionMeta } from "./index"; +import { suggestion } from "./emoji-suggestion"; const extension: ExtensionMeta = { name: "emoji", @@ -27,6 +28,7 @@ const extension: ExtensionMeta = { const { Emoji } = await import("@tiptap-pro/extension-emoji"); return Emoji.configure({ enableEmoticons: props.emojiEnableEmoticons, + suggestion, }); }, }; diff --git a/src/messages.json b/src/messages.json index e1966c6..e46ab9a 100644 --- a/src/messages.json +++ b/src/messages.json @@ -21,7 +21,8 @@ "table_toggle_header_row": "Toggle header row", "table_toggle_header_column": "Toggle header column", "table_toggle_header_cell": "Toggle header cell", - "invisible_characters": "Invisible characters" + "invisible_characters": "Invisible characters", + "emoji": "Insert emoji" } }, "fr": { @@ -46,7 +47,8 @@ "table_toggle_header_row": "Basculer la ligne d'en-tête", "table_toggle_header_column": "Basculer la colonne d'en-tête", "table_toggle_header_cell": "Basculer la cellule d'en-tête", - "invisible_characters": "Caractères invisibles" + "invisible_characters": "Caractères invisibles", + "emoji": "Insérer un émoji" } } } diff --git a/src/tiptap-editor.vue b/src/tiptap-editor.vue index d61c670..206f6f8 100644 --- a/src/tiptap-editor.vue +++ b/src/tiptap-editor.vue @@ -332,6 +332,22 @@ + +