diff --git a/ui/packages/editor/package.json b/ui/packages/editor/package.json index 415ef2ac1..b6a8938df 100644 --- a/ui/packages/editor/package.json +++ b/ui/packages/editor/package.json @@ -82,12 +82,14 @@ "floating-vue": "2.0.0-beta.24", "github-markdown-css": "^5.2.0", "highlight.js": "11.8.0", + "linkifyjs": "^4.1.3", "lowlight": "^3.0.0", "scroll-into-view-if-needed": "^3.1.0", "tippy.js": "^6.3.7" }, "devDependencies": { "@iconify/json": "^2.2.117", + "@types/linkifyjs": "^2.1.7", "release-it": "^16.1.5", "vite-plugin-dts": "^3.7.3" }, diff --git a/ui/packages/editor/src/extensions/link/LinkBubbleButton.vue b/ui/packages/editor/src/extensions/link/LinkBubbleButton.vue index e1fd1e3af..8ed831c35 100644 --- a/ui/packages/editor/src/extensions/link/LinkBubbleButton.vue +++ b/ui/packages/editor/src/extensions/link/LinkBubbleButton.vue @@ -3,7 +3,9 @@ import { computed, type Component } from "vue"; import { VTooltip, Dropdown as VDropdown } from "floating-vue"; import MdiLinkVariant from "~icons/mdi/link-variant"; import { i18n } from "@/locales"; -import type { Editor } from "@/tiptap/vue-3"; +import { type Editor } from "@/tiptap/vue-3"; +import { test } from "linkifyjs"; +import { TextSelection } from "@tiptap/pm/state"; const props = defineProps<{ editor: Editor; @@ -39,10 +41,44 @@ const target = computed({ }); }, }); + +/** + * Convert the currently selected text when clicking the link + */ +const handleLinkBubbleButton = () => { + if (props.isActive({ editor: props.editor })) { + return; + } + const { state } = props.editor; + const { selection } = state; + const { empty } = selection; + + if (selection instanceof TextSelection) { + if (empty) { + return false; + } + const { content } = selection.content(); + if (!content || content.childCount !== 1) { + return false; + } + const text = content.firstChild?.textContent; + if (text && test(text, "url")) { + props.editor.commands.setLink({ + href: text, + target: "_self", + }); + } + } +};