diff --git a/src/clipboard.ts b/src/clipboard.ts index f1654b25..82218de3 100644 --- a/src/clipboard.ts +++ b/src/clipboard.ts @@ -14,6 +14,13 @@ type ElementsClipboard = { elements: ExcalidrawElement[]; }; +export interface ClipboardData { + spreadsheet?: Spreadsheet; + elements?: readonly ExcalidrawElement[]; + text?: string; + errorMessage?: string; +} + let CLIPBOARD = ""; let PREFER_APP_CLIPBOARD = false; @@ -110,12 +117,7 @@ const getSystemClipboard = async ( */ export const parseClipboard = async ( event: ClipboardEvent | null, -): Promise<{ - spreadsheet?: Spreadsheet; - elements?: readonly ExcalidrawElement[]; - text?: string; - errorMessage?: string; -}> => { +): Promise => { const systemClipboard = await getSystemClipboard(event); // if system clipboard empty, couldn't be resolved, or contains previously diff --git a/src/components/App.tsx b/src/components/App.tsx index 6664ebfb..2eedb684 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -1188,6 +1188,11 @@ class App extends React.Component { return; } const data = await parseClipboard(event); + if (this.props.onPaste) { + if (await this.props.onPaste(data, event)) { + return; + } + } if (data.errorMessage) { this.setState({ errorMessage: data.errorMessage }); } else if (data.spreadsheet) { diff --git a/src/packages/excalidraw/CHANGELOG.md b/src/packages/excalidraw/CHANGELOG.md index 23751024..522abf7b 100644 --- a/src/packages/excalidraw/CHANGELOG.md +++ b/src/packages/excalidraw/CHANGELOG.md @@ -13,6 +13,10 @@ Please add the latest change on the top under the correct section. ## Unreleased +## Excalidraw API + +- Add `onPaste` prop to handle custom clipboard behaviours [#3420](https://github.com/excalidraw/excalidraw/pull/3420). + ## Excalidraw Library ### Features diff --git a/src/packages/excalidraw/README_NEXT.md b/src/packages/excalidraw/README_NEXT.md index 9d31a7a5..ffef9912 100644 --- a/src/packages/excalidraw/README_NEXT.md +++ b/src/packages/excalidraw/README_NEXT.md @@ -364,6 +364,7 @@ To view the full example visit :point_down: | [`theme`](#theme) | `light` or `dark` | | The theme of the Excalidraw component | | [`name`](#name) | string | | Name of the drawing | | [`UIOptions`](#UIOptions) |
{ canvasActions:  CanvasActions }
| [DEFAULT UI OPTIONS](https://github.com/excalidraw/excalidraw/blob/master/src/constants.ts#L129) | To customise UI options. Currently we support customising [`canvas actions`](#canvasActions) | +| [`onPaste`](#onPaste) |
(data: ClipboardData, event: ClipboardEvent | null) => boolean
| | Callback to be triggered if passed when the something is pasted in to the scene | ### Dimensions of Excalidraw @@ -528,7 +529,7 @@ This prop controls Excalidraw's theme. When supplied, the value takes precedence This prop sets the name of the drawing which will be used when exporting the drawing. When supplied, the value takes precedence over `intialData.appState.name`, the `name` will be fully controlled by host app and the users won't be able to edit from within Excalidraw. -### `UIOptions` +#### `UIOptions` This prop can be used to customise UI of Excalidraw. Currently we support customising only [`canvasActions`](#canvasActions). It accepts the below parameters @@ -536,7 +537,7 @@ This prop can be used to customise UI of Excalidraw. Currently we support custom { canvasActions: CanvasActions } -#### canvasActions +##### canvasActions | Attribute | Type | Default | Description | | --- | --- | --- | --- | @@ -548,6 +549,18 @@ This prop can be used to customise UI of Excalidraw. Currently we support custom | `saveScene` | boolean | true | Implies whether to show `Save button` | | `theme` | boolean | true | Implies whether to show `Theme toggle` | +#### `onPaste` + +This callback is triggered if passed when something is pasted into the scene. You can use this callback in case you want to do something additional when the paste event occurs. + +
+(data: ClipboardData, event: ClipboardEvent | null) => boolean
+
+ +This callback must return a `boolean` value or a [promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise) which resolves to a boolean value. + +In case you want to prevent the excalidraw paste action you must return `true`, it will stop the native excalidraw clipboard management flow (nothing will be pasted into the scene). + ### Does it support collaboration ? No Excalidraw package doesn't come with collaboration, since this would have different implementations on the consumer so we expose the API's which you can use to communicate with Excalidraw as mentioned above. If you are interested in understanding how Excalidraw does it you can check it [here](https://github.com/excalidraw/excalidraw/blob/master/src/excalidraw-app/index.tsx). diff --git a/src/packages/excalidraw/index.tsx b/src/packages/excalidraw/index.tsx index 7f1e7f37..52823a8f 100644 --- a/src/packages/excalidraw/index.tsx +++ b/src/packages/excalidraw/index.tsx @@ -29,6 +29,7 @@ const Excalidraw = (props: ExcalidrawProps) => { theme, name, renderCustomStats, + onPaste, } = props; const canvasActions = props.UIOptions?.canvasActions; @@ -78,6 +79,7 @@ const Excalidraw = (props: ExcalidrawProps) => { name={name} renderCustomStats={renderCustomStats} UIOptions={UIOptions} + onPaste={onPaste} /> ); diff --git a/src/types.ts b/src/types.ts index a69732b8..4cf26f8d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -20,6 +20,7 @@ import { ExcalidrawImperativeAPI } from "./components/App"; import type { ResolvablePromise } from "./utils"; import { Spreadsheet } from "./charts"; import { Language } from "./i18n"; +import { ClipboardData } from "./clipboard"; export type Point = Readonly; @@ -177,6 +178,10 @@ export interface ExcalidrawProps { appState: AppState, canvas: HTMLCanvasElement | null, ) => void; + onPaste?: ( + data: ClipboardData, + event: ClipboardEvent | null, + ) => Promise | boolean; renderFooter?: (isMobile: boolean) => JSX.Element; langCode?: Language["code"]; viewModeEnabled?: boolean;