diff --git a/src/components/panels/PanelExport.tsx b/src/components/panels/PanelExport.tsx index 81bee94c..8b924033 100644 --- a/src/components/panels/PanelExport.tsx +++ b/src/components/panels/PanelExport.tsx @@ -1,17 +1,35 @@ import React from "react"; import { EditableText } from "../EditableText"; import { Panel } from "../Panel"; +import { ExportType } from "../../scene/types"; + +import "./panelExport.scss"; interface PanelExportProps { projectName: string; onProjectNameChange: (name: string) => void; - onExportAsPNG: React.MouseEventHandler; + onExportCanvas: (type: ExportType) => void; exportBackground: boolean; onExportBackgroundChange: (val: boolean) => void; onSaveScene: React.MouseEventHandler; onLoadScene: React.MouseEventHandler; } +// fa-clipboard +const ClipboardIcon = () => ( + + + +); + +const probablySupportsClipboard = + "toBlob" in HTMLCanvasElement.prototype && + "write" in navigator.clipboard && + "ClipboardItem" in window; + export const PanelExport: React.FC = ({ projectName, exportBackground, @@ -19,7 +37,7 @@ export const PanelExport: React.FC = ({ onExportBackgroundChange, onSaveScene, onLoadScene, - onExportAsPNG + onExportCanvas }) => { return ( @@ -32,7 +50,23 @@ export const PanelExport: React.FC = ({ /> )} Image - Export to png + + onExportCanvas("png")} + > + Export to PNG + + {probablySupportsClipboard && ( + onExportCanvas("clipboard")} + title="Copy to clipboard (experimental)" + > + + + )} + ; +} diff --git a/src/index.tsx b/src/index.tsx index 556aa933..3265582e 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -23,7 +23,7 @@ import { getSelectedAttribute, loadFromJSON, saveAsJSON, - exportAsPNG, + exportCanvas, restoreFromLocalStorage, saveToLocalStorage, hasBackground, @@ -37,6 +37,7 @@ import { import { renderScene } from "./renderer"; import { AppState } from "./types"; import { ExcalidrawElement, ExcalidrawTextElement } from "./element/types"; +import { ExportType } from "./scene/types"; import { getDateTime, isInputLike, measureText } from "./utils"; import { KEYS, META_KEY, isArrowKey } from "./keys"; @@ -170,9 +171,9 @@ export class App extends React.Component<{}, AppState> { if (event.key === KEYS.ESCAPE) { elements = clearSelection(elements); this.forceUpdate(); - this.setState({ elementType: 'selection' }); + this.setState({ elementType: "selection" }); if (window.document.activeElement instanceof HTMLElement) { - window.document.activeElement.blur() + window.document.activeElement.blur(); } event.preventDefault(); return; @@ -614,8 +615,8 @@ export class App extends React.Component<{}, AppState> { - exportAsPNG(elements, this.canvas!, this.state) + onExportCanvas={(type: ExportType) => + exportCanvas(type, elements, this.canvas!, this.state) } exportBackground={this.state.exportBackground} onExportBackgroundChange={val => diff --git a/src/scene/data.ts b/src/scene/data.ts index 16309e8f..f99f88da 100644 --- a/src/scene/data.ts +++ b/src/scene/data.ts @@ -6,6 +6,7 @@ import { getElementAbsoluteCoords } from "../element"; import { renderScene } from "../renderer"; import { AppState } from "../types"; +import { ExportType } from "./types"; import nanoid from "nanoid"; const LOCAL_STORAGE_KEY = "excalidraw"; @@ -76,7 +77,8 @@ export function loadFromJSON() { }); } -export function exportAsPNG( +export function exportCanvas( + type: ExportType, elements: readonly ExcalidrawElement[], canvas: HTMLCanvasElement, { @@ -136,7 +138,23 @@ export function exportAsPNG( } ); - saveFile(`${name}.png`, tempCanvas.toDataURL("image/png")); + if (type === "png") { + saveFile(`${name}.png`, tempCanvas.toDataURL("image/png")); + } else if (type === "clipboard") { + try { + tempCanvas.toBlob(async function(blob) { + try { + await navigator.clipboard.write([ + new window.ClipboardItem({ "image/png": blob }) + ]); + } catch (err) { + window.alert("Couldn't copy to clipboard. Try using Chrome browser."); + } + }); + } catch (err) { + window.alert("Couldn't copy to clipboard. Try using Chrome browser."); + } + } // clean up the DOM if (tempCanvas !== canvas) tempCanvas.remove(); diff --git a/src/scene/index.ts b/src/scene/index.ts index 171315f4..e812a827 100644 --- a/src/scene/index.ts +++ b/src/scene/index.ts @@ -8,7 +8,7 @@ export { getSelectedAttribute } from "./selection"; export { - exportAsPNG, + exportCanvas, loadFromJSON, saveAsJSON, restoreFromLocalStorage, diff --git a/src/scene/types.ts b/src/scene/types.ts index c8904dca..ef9bd7d2 100644 --- a/src/scene/types.ts +++ b/src/scene/types.ts @@ -15,3 +15,5 @@ export type SceneScroll = { export interface Scene { elements: ExcalidrawTextElement[]; } + +export type ExportType = "png" | "clipboard";