Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: export exportToClipboard util from package #5103

Merged
merged 7 commits into from Apr 29, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 9 additions & 7 deletions src/clipboard.ts
Expand Up @@ -57,19 +57,21 @@ const clipboardContainsElements = (
export const copyToClipboard = async (
elements: readonly NonDeletedExcalidrawElement[],
appState: AppState,
files: BinaryFiles,
files: BinaryFiles | null,
) => {
// select binded text elements when copying
const selectedElements = getSelectedElements(elements, appState, true);
const contents: ElementsClipboard = {
type: EXPORT_DATA_TYPES.excalidrawClipboard,
elements: selectedElements,
files: selectedElements.reduce((acc, element) => {
if (isInitializedImageElement(element) && files[element.fileId]) {
acc[element.fileId] = files[element.fileId];
}
return acc;
}, {} as BinaryFiles),
files: files
? selectedElements.reduce((acc, element) => {
if (isInitializedImageElement(element) && files[element.fileId]) {
acc[element.fileId] = files[element.fileId];
}
return acc;
}, {} as BinaryFiles)
: undefined,
};
const json = JSON.stringify(contents);
CLIPBOARD = json;
Expand Down
1 change: 1 addition & 0 deletions src/packages/excalidraw/CHANGELOG.md
Expand Up @@ -17,6 +17,7 @@ Please add the latest change on the top under the correct section.

#### Features

- Expose util `exportToClipboard`[https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#exportToClipboard] which allows to copy the scene contents to clipboard as `svg`, `png` or `text` [#5103](https://github.com/excalidraw/excalidraw/pull/5103).
- Expose `window.EXCALIDRAW_EXPORT_SOURCE` which you can use to overwrite the `source` field in exported data [#5095](https://github.com/excalidraw/excalidraw/pull/5095).
- The `exportToBlob` utility now supports the `exportEmbedScene` option when generating a png image [#5047](https://github.com/excalidraw/excalidraw/pull/5047).
- Exported [`restoreLibraryItems`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#restoreLibraryItems) API [#4995](https://github.com/excalidraw/excalidraw/pull/4995).
Expand Down
30 changes: 29 additions & 1 deletion src/packages/excalidraw/README_NEXT.md
Expand Up @@ -857,7 +857,7 @@ This function returns the canvas with the exported elements, appState and dimens

<pre>
exportToBlob(
opts: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/packages/utils.ts#L10">ExportOpts</a> & {
opts: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/packages/utils.ts#L14">ExportOpts</a> & {
mimeType?: string,
quality?: number;
})
Expand Down Expand Up @@ -900,6 +900,34 @@ exportToSvg({

This function returns a promise which resolves to svg of the exported drawing.

#### `exportToClipboard`

**_Signature_**

<pre>
exportToClipboard(
opts: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/packages/utils.ts#L14">ExportOpts</a> & {
mimeType?: string,
quality?: number;
type: 'png' | 'svg' |'text'
})
</pre>

| Name | Type | Default | Description |
| --- | --- | --- | --- | --- | --- |
| opts | | | This param is same as the params passed to `exportToCanvas`. You can refer to [`exportToCanvas`](#exportToCanvas). |
| mimeType | string | "image/png" | Indicates the image format, this will be used when exporting as `png`. |
| quality | number | 0.92 | A value between 0 and 1 indicating the [image quality](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob#parameters). Applies only to `image/jpeg`/`image/webp` MIME types. This will be used when exporting as `png`. |
| type | 'png' | 'svg' | 'text' | | This determines the format to which the scene data should be exported. |

**How to use**

```js
import { exportToClipboard } from "@excalidraw/excalidraw-next";
```

Copies the scene data in the specified format (determined by `type`) to clipboard.

##### Additional attributes of appState for `export\*` APIs

| Name | Type | Default | Description |
Expand Down
29 changes: 27 additions & 2 deletions src/packages/excalidraw/example/App.js
Expand Up @@ -10,8 +10,13 @@ import { MIME_TYPES } from "../../../constants";
// This is so that we use the bundled excalidraw.development.js file instead
// of the actual source code

const { exportToCanvas, exportToSvg, exportToBlob, Excalidraw } =
window.ExcalidrawLib;
const {
exportToCanvas,
exportToSvg,
exportToBlob,
exportToClipboard,
Excalidraw,
} = window.ExcalidrawLib;
const resolvablePromise = () => {
let resolve;
let reject;
Expand Down Expand Up @@ -141,6 +146,14 @@ export default function App() {
}
}, []);

const onCopy = async (type) => {
await exportToClipboard({
elements: excalidrawRef.current.getSceneElements(),
appState: excalidrawRef.current.getAppState(),
type,
});
window.alert(`Copied to clipboard as ${type} sucessfully`);
};
return (
<div className="App">
<h1> Excalidraw Example</h1>
Expand Down Expand Up @@ -175,6 +188,7 @@ export default function App() {
>
Update Library
</button>

<label>
<input
type="checkbox"
Expand Down Expand Up @@ -213,6 +227,17 @@ export default function App() {
/>
Switch to Dark Theme
</label>
<div>
<button onClick={onCopy.bind(null, "png")}>
Copy to Clipboard as PNG
</button>
<button onClick={onCopy.bind(null, "svg")}>
Copy to Clipboard as SVG
</button>
<button onClick={onCopy.bind(null, "text")}>
Copy to Clipboard as Text
</button>
</div>
</div>
<div className="excalidraw-wrapper">
<Excalidraw
Expand Down
1 change: 1 addition & 0 deletions src/packages/excalidraw/index.tsx
Expand Up @@ -197,6 +197,7 @@ export {
loadLibraryFromBlob,
loadFromBlob,
getFreeDrawSvgPath,
exportToClipboard,
} from "../../packages/utils";
export { isLinearElement } from "../../element/typeChecks";

Expand Down
41 changes: 38 additions & 3 deletions src/packages/utils.ts
Expand Up @@ -10,6 +10,11 @@ import { restore } from "../data/restore";
import { MIME_TYPES } from "../constants";
import { encodePngMetadata } from "../data/image";
import { serializeAsJSON } from "../data/json";
import {
copyBlobToClipboardAsPng,
copyTextToSystemClipboard,
copyToClipboard,
} from "../clipboard";

type ExportOpts = {
elements: readonly NonDeleted<ExcalidrawElement>[];
Expand Down Expand Up @@ -81,7 +86,7 @@ export const exportToBlob = async (
mimeType?: string;
quality?: number;
},
): Promise<Blob | null> => {
): Promise<Blob> => {
let { mimeType = MIME_TYPES.png, quality } = opts;

if (mimeType === MIME_TYPES.png && typeof quality === "number") {
Expand All @@ -107,9 +112,12 @@ export const exportToBlob = async (

quality = quality ? quality : /image\/jpe?g/.test(mimeType) ? 0.92 : 0.8;

return new Promise((resolve) => {
return new Promise((resolve, reject) => {
canvas.toBlob(
async (blob: Blob | null) => {
async (blob) => {
if (!blob) {
return reject(new Error("couldn't export to blob"));
}
if (
blob &&
mimeType === MIME_TYPES.png &&
Expand Down Expand Up @@ -156,6 +164,33 @@ export const exportToSvg = async ({
);
};

export const exportToClipboard = async (
opts: ExportOpts & {
mimeType?: string;
quality?: number;
type: "png" | "svg" | "text";
ad1992 marked this conversation as resolved.
Show resolved Hide resolved
},
) => {
if (opts.type === "svg") {
const svg = await exportToSvg(opts);
await copyTextToSystemClipboard(svg.outerHTML);
} else if (opts.type === "png") {
await copyBlobToClipboardAsPng(exportToBlob(opts));
} else if (opts.type === "text") {
const appState = {
offsetTop: 0,
offsetLeft: 0,
width: 0,
height: 0,
...getDefaultAppState(),
...opts.appState,
};
await copyToClipboard(opts.elements, appState, opts.files);
} else {
throw new Error("Invalid export type");
}
};

export { serializeAsJSON, serializeLibraryAsJSON } from "../data/json";
export { loadFromBlob, loadLibraryFromBlob } from "../data/blob";
export { getFreeDrawSvgPath } from "../renderer/renderElement";