fix: link paste handler (#609)

* feat: support pasting markdown

* fix link paste handler
This commit is contained in:
Philip Okugbe
2025-01-04 20:47:49 +00:00
committed by GitHub
parent 287b833838
commit f5bc99b449
4 changed files with 48 additions and 6 deletions

View File

@ -65,6 +65,7 @@
"fractional-indexing-jittered": "^0.9.1", "fractional-indexing-jittered": "^0.9.1",
"ioredis": "^5.4.1", "ioredis": "^5.4.1",
"jszip": "^3.10.1", "jszip": "^3.10.1",
"linkifyjs": "^4.2.0",
"marked": "^13.0.3", "marked": "^13.0.3",
"uuid": "^11.0.3", "uuid": "^11.0.3",
"y-indexeddb": "^9.0.12", "y-indexeddb": "^9.0.12",

View File

@ -10,11 +10,35 @@ export const LinkExtension = TiptapLink.extend({
return [ return [
{ {
tag: 'a[href]:not([data-type="button"]):not([href *= "javascript:" i])', tag: 'a[href]:not([data-type="button"]):not([href *= "javascript:" i])',
getAttrs: (element) => {
if (
element
.getAttribute("href")
?.toLowerCase()
.startsWith("javascript:")
) {
return false;
}
return null;
},
}, },
]; ];
}, },
renderHTML({ HTMLAttributes }) { renderHTML({ HTMLAttributes }) {
if (HTMLAttributes.href?.toLowerCase().startsWith("javascript:")) {
return [
"a",
mergeAttributes(
this.options.HTMLAttributes,
{ ...HTMLAttributes, href: "" },
{ class: "link" },
),
0,
];
}
return [ return [
"a", "a",
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, { mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {

View File

@ -3,9 +3,15 @@ import { Extension } from "@tiptap/core";
import { Plugin, PluginKey } from "@tiptap/pm/state"; import { Plugin, PluginKey } from "@tiptap/pm/state";
import { DOMParser } from "@tiptap/pm/model"; import { DOMParser } from "@tiptap/pm/model";
import { markdownToHtml } from "./utils/marked.utils"; import { markdownToHtml } from "./utils/marked.utils";
import { find } from "linkifyjs";
export const MarkdownClipboard = Extension.create({ export const MarkdownClipboard = Extension.create({
name: "markdownClipboard", name: "markdownClipboard",
priority: 50,
export const MarkdownClipboard = Extension.create({
name: "markdownClipboard",
addOptions() { addOptions() {
return { return {
transformPastedText: false, transformPastedText: false,
@ -17,9 +23,17 @@ export const MarkdownClipboard = Extension.create({
key: new PluginKey("markdownClipboard"), key: new PluginKey("markdownClipboard"),
props: { props: {
clipboardTextParser: (text, context, plainText) => { clipboardTextParser: (text, context, plainText) => {
if (plainText || !this.options.transformPastedText) {
return null; // pasting with shift key prevents formatting const link = find(text, {
defaultProtocol: "http",
}).find((item) => item.isLink && item.value === text);
if (plainText || !this.options.transformPastedText || link) {
// don't parse plaintext link to allow link paste handler to work
// pasting with shift key prevents formatting
return null;
} }
const parsed = markdownToHtml(text); const parsed = markdownToHtml(text);
return DOMParser.fromSchema(this.editor.schema).parseSlice( return DOMParser.fromSchema(this.editor.schema).parseSlice(
elementFromString(parsed), elementFromString(parsed),

11
pnpm-lock.yaml generated
View File

@ -160,6 +160,9 @@ importers:
jszip: jszip:
specifier: ^3.10.1 specifier: ^3.10.1
version: 3.10.1 version: 3.10.1
linkifyjs:
specifier: ^4.2.0
version: 4.2.0
marked: marked:
specifier: ^13.0.3 specifier: ^13.0.3
version: 13.0.3 version: 13.0.3
@ -6459,8 +6462,8 @@ packages:
linkify-it@5.0.0: linkify-it@5.0.0:
resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==}
linkifyjs@4.1.3: linkifyjs@4.2.0:
resolution: {integrity: sha512-auMesunaJ8yfkHvK4gfg1K0SaKX/6Wn9g2Aac/NwX+l5VdmFZzo/hdPGxEOETj+ryRa4/fiOPjeeKURSAJx1sg==} resolution: {integrity: sha512-pCj3PrQyATaoTYKHrgWRF3SJwsm61udVh+vuls/Rl6SptiDhgE7ziUIudAedRY9QEfynmM7/RmLEfPUyw1HPCw==}
loader-runner@4.3.0: loader-runner@4.3.0:
resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==}
@ -12349,7 +12352,7 @@ snapshots:
dependencies: dependencies:
'@tiptap/core': 2.10.3(@tiptap/pm@2.10.3) '@tiptap/core': 2.10.3(@tiptap/pm@2.10.3)
'@tiptap/pm': 2.10.3 '@tiptap/pm': 2.10.3
linkifyjs: 4.1.3 linkifyjs: 4.2.0
'@tiptap/extension-list-item@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))': '@tiptap/extension-list-item@2.10.3(@tiptap/core@2.10.3(@tiptap/pm@2.10.3))':
dependencies: dependencies:
@ -15922,7 +15925,7 @@ snapshots:
dependencies: dependencies:
uc.micro: 2.1.0 uc.micro: 2.1.0
linkifyjs@4.1.3: {} linkifyjs@4.2.0: {}
loader-runner@4.3.0: {} loader-runner@4.3.0: {}