ExternalContentManager for handling external content (files, images, etc) (#1550)

This PR improves the editor's APIs around creating assets and files.
This allows end user developers to replace behavior that might occur,
for example, when pasting images or dragging files onto the canvas.

Here, we:
- remove `onCreateAssetFromFile` prop
- remove `onCreateBookmarkFromUrl` prop
- introduce `onEditorReady` prop
- introduce `onEditorWillDispose` prop
- introduce `ExternalContentManager`

The `ExternalContentManager` (ECM) is used in circumstances where we're
turning external content (text, images, urls, etc) into assets or
shapes. It is designed to allow certain methods to be overwritten by
other developers as a kind of weakly supported hack.

For example, when a user drags an image onto the canvas, the event
handler passes a `TLExternalContent` object to the editor's
`putExternalContent` method. This method runs the ECM's handler for this
content type. That handler may in turn run other methods, such as
`createAssetFromFile` or `createShapesForAssets`, which will lead to the
image being created on the canvas.

If a developer wanted to change the way that assets are created from
files, then they could overwrite that method at runtime.

```ts
const handleEditorReady = (editor: Editor) => {
  editor.externalContentManager.createAssetFromFile = myHandler
}

function Example() {
  return <Tldraw onEditorReady={handleEditorReady}/>
}
```

If you wanted to go even deeper, you could override the editor's
`putExternalContent` method.

```ts
const handleEditorReady = (editor: Editor) => {
const handleExternalContent = (info: TLExternalContent): Promise<void> => {
	if (info.type === 'files') {
	   // do something here
	} else {
          // do the normal thing
          editor.externalContentManager.handleContent(info)
        }
}
```

### Change Type

- [x] `major`

### Test Plan

1. Drag images, urls, etc. onto the canvas
2. Use copy and paste for single and multiple files
3. Use bookmark / embed shapes and convert between eachother

### Release Notes

- [editor] add `ExternalContentManager` for plopping content onto the
canvas
- [editor] remove `onCreateAssetFromFile` prop
- [editor] remove `onCreateBookmarkFromUrl` prop
- [editor] introduce `onEditorReady` prop
- [editor] introduce `onEditorWillDispose` prop
- [editor] introduce `ExternalContentManager`
This commit is contained in:
Steve Ruiz 2023-06-08 15:53:11 +01:00 committed by GitHub
parent f2e95988e0
commit 0cc91eec62
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 817 additions and 726 deletions

View file

@ -1,5 +1,4 @@
import React, { useMemo } from 'react'
import { createShapesFromFiles } from '../utils/assets'
import { preventDefault, releasePointerCapture, setPointerCapture } from '../utils/dom'
import { getPointerInfo } from '../utils/svg'
import { useEditor } from './useEditor'
@ -107,7 +106,12 @@ export function useCanvasEvents() {
(file) => !file.name.endsWith('.tldr')
)
await createShapesFromFiles(editor, files, editor.screenToPage(e.clientX, e.clientY), false)
await editor.putExternalContent({
type: 'files',
files,
point: editor.screenToPage(e.clientX, e.clientY),
ignoreParent: false,
})
}
return {