diff --git a/packages/core/src/api/clipboard/fromClipboard/acceptedMIMETypes.ts b/packages/core/src/api/clipboard/fromClipboard/acceptedMIMETypes.ts index c79400c78a..6aebb17513 100644 --- a/packages/core/src/api/clipboard/fromClipboard/acceptedMIMETypes.ts +++ b/packages/core/src/api/clipboard/fromClipboard/acceptedMIMETypes.ts @@ -1,6 +1,6 @@ export const acceptedMIMETypes = [ "vscode-editor-data", - "blocknote/html", + "blocknote/json", "text/markdown", "text/html", "text/plain", diff --git a/packages/core/src/api/clipboard/fromClipboard/pasteExtension.ts b/packages/core/src/api/clipboard/fromClipboard/pasteExtension.ts index a0eb03889e..3655698491 100644 --- a/packages/core/src/api/clipboard/fromClipboard/pasteExtension.ts +++ b/packages/core/src/api/clipboard/fromClipboard/pasteExtension.ts @@ -14,6 +14,8 @@ import { import { acceptedMIMETypes } from "./acceptedMIMETypes.js"; import { handleFileInsertion } from "./handleFileInsertion.js"; import { handleVSCodePaste } from "./handleVSCodePaste.js"; +import { Slice } from "prosemirror-model"; +import { getPmSchema } from "../../pmUtil.js"; function defaultPasteHandler({ event, @@ -68,9 +70,13 @@ function defaultPasteHandler({ const data = event.clipboardData!.getData(format); - if (format === "blocknote/html") { - // Is blocknote/html, so no need to convert it - editor.pasteHTML(data, true); + if (format === "blocknote/json") { + editor.transact((tr) => { + const schema = getPmSchema(tr); + const slice = Slice.fromJSON(schema, JSON.parse(data)); + // Probably need to expand the selection to the block that is being pasted into? + tr.replaceSelection(slice); + }); return true; } diff --git a/packages/core/src/api/clipboard/toClipboard/copyExtension.ts b/packages/core/src/api/clipboard/toClipboard/copyExtension.ts index e5f4fec1bd..ffe2ccc287 100644 --- a/packages/core/src/api/clipboard/toClipboard/copyExtension.ts +++ b/packages/core/src/api/clipboard/toClipboard/copyExtension.ts @@ -1,5 +1,5 @@ import { Extension } from "@tiptap/core"; -import { Fragment, Node } from "prosemirror-model"; +import { Fragment, Node, Slice } from "prosemirror-model"; import { NodeSelection, Plugin } from "prosemirror-state"; import { CellSelection } from "prosemirror-tables"; import type { EditorView } from "prosemirror-view"; @@ -111,6 +111,7 @@ export function selectedFragmentToHTML< clipboardHTML: string; externalHTML: string; markdown: string; + slice: Slice; } { // Checks if a `blockContent` node is being copied and expands // the selection to the parent `blockContainer` node. This is @@ -127,22 +128,21 @@ export function selectedFragmentToHTML< ); } + const slice = view.state.selection.content(); // Uses default ProseMirror clipboard serialization. - const clipboardHTML: string = view.serializeForClipboard( - view.state.selection.content(), - ).dom.innerHTML; - - const selectedFragment = view.state.selection.content().content; + const clipboardHTML: string = view.serializeForClipboard(slice).dom.innerHTML; + // TODO should probably remove this and just use the slice.toJSON() + // Kept it so that the tests still pass const externalHTML = fragmentToExternalHTML( view, - selectedFragment, + slice.content, editor, ); const markdown = cleanHTMLToMarkdown(externalHTML); - return { clipboardHTML, externalHTML, markdown }; + return { clipboardHTML, externalHTML, markdown, slice }; } const checkIfSelectionInNonEditableBlock = () => { @@ -186,14 +186,17 @@ const copyToClipboard = < event.preventDefault(); event.clipboardData!.clearData(); - const { clipboardHTML, externalHTML, markdown } = selectedFragmentToHTML( + const { externalHTML, markdown, slice } = selectedFragmentToHTML( view, editor, ); // TODO: Writing to other MIME types not working in Safari for // some reason. - event.clipboardData!.setData("blocknote/html", clipboardHTML); + event.clipboardData!.setData( + "blocknote/json", + JSON.stringify(slice.toJSON()), + ); event.clipboardData!.setData("text/html", externalHTML); event.clipboardData!.setData("text/plain", markdown); }; @@ -263,12 +266,15 @@ export const createCopyToClipboardExtension = < event.preventDefault(); event.dataTransfer!.clearData(); - const { clipboardHTML, externalHTML, markdown } = + const { externalHTML, markdown, slice } = selectedFragmentToHTML(view, editor); // TODO: Writing to other MIME types not working in Safari for // some reason. - event.dataTransfer!.setData("blocknote/html", clipboardHTML); + event.dataTransfer!.setData( + "blocknote/json", + JSON.stringify(slice.toJSON()), + ); event.dataTransfer!.setData("text/html", externalHTML); event.dataTransfer!.setData("text/plain", markdown); diff --git a/packages/core/src/extensions/SideMenu/SideMenuPlugin.ts b/packages/core/src/extensions/SideMenu/SideMenuPlugin.ts index efb6d5f3e8..bbb683944e 100644 --- a/packages/core/src/extensions/SideMenu/SideMenuPlugin.ts +++ b/packages/core/src/extensions/SideMenu/SideMenuPlugin.ts @@ -1,4 +1,4 @@ -import { DOMParser, Slice } from "@tiptap/pm/model"; +import { Slice } from "@tiptap/pm/model"; import { EditorState, Plugin, @@ -338,7 +338,7 @@ export class SideMenuView< if ( this.sideMenuDetection === "editor" || (event as any).synthetic || - !event.dataTransfer?.types.includes("blocknote/html") + !event.dataTransfer?.types.includes("blocknote/json") ) { return; } @@ -387,8 +387,8 @@ export class SideMenuView< * access `dataTransfer` contents on `dragstart` and `drop` events. */ onDragStart = (event: DragEvent) => { - const html = event.dataTransfer?.getData("blocknote/html"); - if (!html) { + const json = event.dataTransfer?.getData("blocknote/json"); + if (!json) { return; } @@ -396,16 +396,8 @@ export class SideMenuView< throw new Error("New drag was started while an existing drag is ongoing"); } - const element = document.createElement("div"); - element.innerHTML = html; - - const parser = DOMParser.fromSchema(this.pmView.state.schema); - const node = parser.parse(element, { - topNode: this.pmView.state.schema.nodes["blockGroup"].create(), - }); - this.pmView.dragging = { - slice: new Slice(node.content, 0, 0), + slice: Slice.fromJSON(this.pmView.state.schema, JSON.parse(json)), move: true, }; }; @@ -419,7 +411,7 @@ export class SideMenuView< if ( this.sideMenuDetection === "editor" || (event as any).synthetic || - !event.dataTransfer?.types.includes("blocknote/html") + !event.dataTransfer?.types.includes("blocknote/json") ) { return; } diff --git a/packages/core/src/extensions/SideMenu/dragging.ts b/packages/core/src/extensions/SideMenu/dragging.ts index 3eaab54c50..d28594b540 100644 --- a/packages/core/src/extensions/SideMenu/dragging.ts +++ b/packages/core/src/extensions/SideMenu/dragging.ts @@ -196,9 +196,6 @@ export function dragStart< const selectedSlice = view.state.selection.content(); const schema = editor.pmSchema; - const clipboardHTML = - view.serializeForClipboard(selectedSlice).dom.innerHTML; - const externalHTMLExporter = createExternalHTMLExporter(schema, editor); const blocks = fragmentToBlocks(selectedSlice.content); @@ -207,7 +204,10 @@ export function dragStart< const plainText = cleanHTMLToMarkdown(externalHTML); e.dataTransfer.clearData(); - e.dataTransfer.setData("blocknote/html", clipboardHTML); + e.dataTransfer.setData( + "blocknote/json", + JSON.stringify(selectedSlice.toJSON()), + ); e.dataTransfer.setData("text/html", externalHTML); e.dataTransfer.setData("text/plain", plainText); e.dataTransfer.effectAllowed = "move";