UNPKG

@milkdown/plugin-clipboard

Version:

The clipboard plugin of [milkdown](https://milkdown.dev/).

101 lines (100 loc) 3.61 kB
import { schemaCtx, editorViewOptionsCtx, serializerCtx, parserCtx } from "@milkdown/core"; import { getNodeFromSchema, isTextOnlySlice } from "@milkdown/prose"; import { DOMParser, DOMSerializer } from "@milkdown/prose/model"; import { PluginKey, Plugin, TextSelection } from "@milkdown/prose/state"; import { $prose } from "@milkdown/utils"; function isPureText(content) { if (!content) return false; if (Array.isArray(content)) { if (content.length > 1) return false; return isPureText(content[0]); } const child = content.content; if (child) return isPureText(child); return content.type === "text"; } const clipboard = $prose((ctx) => { const schema = ctx.get(schemaCtx); ctx.update(editorViewOptionsCtx, (prev) => ({ ...prev, editable: prev.editable ?? (() => true) })); const key = new PluginKey("MILKDOWN_CLIPBOARD"); const plugin = new Plugin({ key, props: { handlePaste: (view, event) => { const parser = ctx.get(parserCtx); const editable = view.props.editable?.(view.state); const { clipboardData } = event; if (!editable || !clipboardData) return false; const currentNode = view.state.selection.$from.node(); if (currentNode.type.spec.code) return false; const text = clipboardData.getData("text/plain"); const vscodeData = clipboardData.getData("vscode-editor-data"); if (vscodeData) { const data = JSON.parse(vscodeData); const language = data?.mode; if (text && language) { const { tr } = view.state; const codeBlock = getNodeFromSchema("code_block", schema); tr.replaceSelectionWith(codeBlock.create({ language })).setSelection( TextSelection.near( tr.doc.resolve(Math.max(0, tr.selection.from - 2)) ) ).insertText(text.replace(/\r\n?/g, "\n")); view.dispatch(tr); return true; } } const html = clipboardData.getData("text/html"); if (html.length === 0 && text.length === 0) return false; const domParser = DOMParser.fromSchema(schema); let dom; if (html.length === 0) { const slice2 = parser(text); if (!slice2 || typeof slice2 === "string") return false; dom = DOMSerializer.fromSchema(schema).serializeFragment( slice2.content ); } else { const template = document.createElement("template"); template.innerHTML = html; dom = template.content.cloneNode(true); template.remove(); } const slice = domParser.parseSlice(dom); const node = isTextOnlySlice(slice); if (node) { view.dispatch(view.state.tr.replaceSelectionWith(node, true)); return true; } view.dispatch(view.state.tr.replaceSelection(slice)); return true; }, clipboardTextSerializer: (slice) => { const serializer = ctx.get(serializerCtx); const isText = isPureText(slice.content.toJSON()); if (isText) return slice.content.textBetween( 0, slice.content.size, "\n\n" ); const doc = schema.topNodeType.createAndFill(void 0, slice.content); if (!doc) return ""; const value = serializer(doc); return value; } } }); return plugin; }); clipboard.meta = { displayName: "Prose<clipboard>", package: "@milkdown/plugin-clipboard" }; export { clipboard }; //# sourceMappingURL=index.js.map