diff --git a/src/clipboard.ts b/src/clipboard.ts index 10062bb2..876f790f 100644 --- a/src/clipboard.ts +++ b/src/clipboard.ts @@ -97,6 +97,14 @@ export async function copyCanvasToClipboardAsPng(canvas: HTMLCanvasElement) { }); } +export async function copyCanvasToClipboardAsSvg(svgroot: SVGSVGElement) { + try { + await navigator.clipboard.writeText(svgroot.outerHTML); + } catch (error) { + console.error(error); + } +} + export async function copyTextToSystemClipboard(text: string | null) { let copied = false; if (probablySupportsClipboardWriteText) { diff --git a/src/components/App.tsx b/src/components/App.tsx index 913a6992..85f1831d 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -88,6 +88,7 @@ import { copyToAppClipboard, getClipboardContent, probablySupportsClipboardBlob, + probablySupportsClipboardWriteText, } from "../clipboard"; import { normalizeScroll } from "../scene"; import { getCenter, getDistance } from "../gesture"; @@ -565,6 +566,22 @@ export class App extends React.Component { ); }; + private copyToClipboardAsSvg = () => { + const selectedElements = getSelectedElements( + globalSceneState.getAllElements(), + this.state, + ); + exportCanvas( + "clipboard-svg", + selectedElements.length + ? selectedElements + : globalSceneState.getAllElements(), + this.state, + this.canvas!, + this.state, + ); + }; + private onTapStart = (event: TouchEvent) => { if (!didTapTwice) { didTapTwice = true; @@ -2661,6 +2678,11 @@ export class App extends React.Component { label: t("labels.copyAsPng"), action: this.copyToClipboardAsPng, }, + probablySupportsClipboardWriteText && + hasNonDeletedElements(globalSceneState.getAllElements()) && { + label: t("labels.copyAsSvg"), + action: this.copyToClipboardAsSvg, + }, ...this.actionManager.getContextMenuItems((action) => this.canvasOnlyActions.includes(action.name), ), @@ -2689,6 +2711,10 @@ export class App extends React.Component { label: t("labels.copyAsPng"), action: this.copyToClipboardAsPng, }, + probablySupportsClipboardWriteText && { + label: t("labels.copyAsSvg"), + action: this.copyToClipboardAsSvg, + }, ...this.actionManager.getContextMenuItems( (action) => !this.canvasOnlyActions.includes(action.name), ), diff --git a/src/data/index.ts b/src/data/index.ts index 8b51fa29..84a4dda5 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -7,7 +7,10 @@ import { exportToCanvas, exportToSvg } from "../scene/export"; import { fileSave } from "browser-nativefs"; import { t } from "../i18n"; -import { copyCanvasToClipboardAsPng } from "../clipboard"; +import { + copyCanvasToClipboardAsPng, + copyCanvasToClipboardAsSvg, +} from "../clipboard"; import { serializeAsJSON } from "./json"; import { ExportType } from "../scene/types"; @@ -299,16 +302,21 @@ export async function exportCanvas( if (!hasNonDeletedElements(elements)) { return window.alert(t("alerts.cannotExportEmptyCanvas")); } - if (type === "svg") { + if (type === "svg" || type === "clipboard-svg") { const tempSvg = exportToSvg(elements, { exportBackground, viewBackgroundColor, exportPadding, }); - await fileSave(new Blob([tempSvg.outerHTML], { type: "image/svg+xml" }), { - fileName: `${name}.svg`, - }); - return; + if (type === "svg") { + await fileSave(new Blob([tempSvg.outerHTML], { type: "image/svg+xml" }), { + fileName: `${name}.svg`, + }); + return; + } else if (type === "clipboard-svg") { + copyCanvasToClipboardAsSvg(tempSvg); + return; + } } const tempCanvas = exportToCanvas(elements, appState, { diff --git a/src/locales/en.json b/src/locales/en.json index 1731c86c..360eef12 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -4,6 +4,7 @@ "selectAll": "Select All", "copy": "Copy", "copyAsPng": "Copy to clipboard as PNG", + "copyAsSvg": "Copy to clipboard as SVG", "bringForward": "Bring Forward", "sendToBack": "Send To Back", "bringToFront": "Bring To Front", diff --git a/src/scene/types.ts b/src/scene/types.ts index 6a38c5b8..333a39cc 100644 --- a/src/scene/types.ts +++ b/src/scene/types.ts @@ -22,7 +22,12 @@ export interface Scene { elements: ExcalidrawTextElement[]; } -export type ExportType = "png" | "clipboard" | "backend" | "svg"; +export type ExportType = + | "png" + | "clipboard" + | "clipboard-svg" + | "backend" + | "svg"; export type ScrollBars = { horizontal: {