Uploading Files with Uppy
This example allows users to upload files using Uppy (opens in a new tab) and use them in the editor.
Uppy is highly extensible and has an extensive ecosystem of plugins. For example, you can:
- record audio, screen or webcam
- import files from Box / Dropbox / Facebook / Google Drive / Google Photos / Instagram / OneDrive / Zoom
- select files from Unsplash
- show an image editor (crop, rotate, etc)
(in this example, we've enabled the Webcam, ScreenCapture and Image Editor plugin)
Try it out: Click the "Add Image" button and you can either drop files or click "browse files" to upload them.
Relevant Docs:
/* eslint-disable import/no-extraneous-dependencies */
import "@blocknote/core/fonts/inter.css";
import { BlockNoteView } from "@blocknote/mantine";
import "@blocknote/mantine/style.css";
import {
FilePanelController,
FilePanelProps,
useBlockNoteEditor,
useCreateBlockNote,
} from "@blocknote/react";
import { Dashboard } from "@uppy/react/";
import XHR from "@uppy/xhr-upload";
import { useEffect } from "react";
import Uppy, { UploadSuccessCallback } from "@uppy/core";
import "@uppy/core/dist/style.min.css";
import "@uppy/dashboard/dist/style.min.css";
// image editor plugin
import ImageEditor from "@uppy/image-editor";
import "@uppy/image-editor/dist/style.min.css";
// screen capture plugin
import ScreenCapture from "@uppy/screen-capture";
import "@uppy/screen-capture/dist/style.min.css";
// webcam plugin
import Webcam from "@uppy/webcam";
import "@uppy/webcam/dist/style.min.css";
/**
* Configure your Uppy instance here.
*/
const uppy = new Uppy()
/* enable some plugins, you probably want to customize this
* See https://uppy.io/examples/ for all the integrations like Google Drive, Instagram Dropbox etc.
*/
.use(Webcam)
.use(ScreenCapture)
.use(ImageEditor)
/* In this example, we use an XHR upload plugin to upload files to tmpfiles.org,
* you want to replace this with your own upload endpoint or Uppy Companion server
*
*/
.use(XHR, {
endpoint: "https://tmpfiles.org/api/v1/upload",
getResponseData(text, resp) {
return {
url: JSON.parse(text).data.url.replace(
"tmpfiles.org/",
"tmpfiles.org/dl/"
),
};
},
});
function UppyFilePanel(props: FilePanelProps) {
const { block } = props;
const editor = useBlockNoteEditor();
useEffect(() => {
/**
* Listen for successful tippy uploads, and then update the Block with the uploaded URL
*/
const handler: UploadSuccessCallback<Record<string, unknown>> = (
file,
response
) => {
if (!file) {
return;
}
if (file.source === "uploadFile") {
// didn't originate from Dashboard. Should be handled by `uploadFile`
return;
}
if (response.status === 200) {
// get the correct URL ()
const updateData = {
props: {
name: file?.name,
url: response.uploadURL,
},
};
editor.updateBlock(block, updateData);
// File should be removed from the uppy instance after successful upload.
uppy.removeFile(file.id);
}
};
uppy.on("upload-success", handler);
return () => {
uppy.off("upload-success", handler);
};
}, [block, editor]);
// set up dashboard as in https://uppy.io/examples/
return <Dashboard uppy={uppy} width={400} height={500} />;
}
/**
* Implementation for the BlockNote `uploadFile` function.
*
* This function is used when for example, files are dropped into the editor
*/
async function uploadFile(file: File) {
const id = uppy.addFile({
id: file.name,
name: file.name,
type: file.type,
data: file,
source: "uploadFile",
});
try {
const result = await uppy.upload();
return result.successful[0].response!.uploadURL!;
} finally {
uppy.removeFile(id);
}
}
export default function App() {
// Creates a new editor instance.
const editor = useCreateBlockNote({
initialContent: [
{
type: "paragraph",
content: "Welcome to this demo!",
},
{
type: "paragraph",
content: "Upload an image using the button below",
},
{
type: "image",
},
],
uploadFile,
});
// Renders the editor instance using a React component.
return (
<BlockNoteView editor={editor} filePanel={false}>
<FilePanelController filePanel={UppyFilePanel} />
</BlockNoteView>
);
}