Slate Cloud
In Getting Started, we added support for uploading by pasting files into or dropping files onto the editor. We did this by adding editor.cloud.handlePaste
and editor.cloud.handleDrop
to the Editable
component.
<Editable
renderElement={renderElement}
onPaste={editor.cloud.handlePaste}
onDrop={editor.cloud.handleDrop}
/>
Sometimes, you want to upload files using another method like opening a File picker or working with a File
object.
Slate Cloud has two functions for uploading files:
To upload from an <input type="file" />
element, add the editor.cloud.onInputFileChangeHandler
to the onChange
attribute.
import { useState } from "react"import { createEditor } from "slate"import { withHistory } from "slate-history"import { Editable, Slate, withReact } from "slate-react"import { withCloud } from "slate-cloud"import { CloudComponents } from "slate-cloud/cloud-components"
const renderElement = CloudComponents.withRenderElement((props) => { const { element } = props if (element.type === "paragraph") { return <p {...props.attributes}>{props.children}</p> } throw new Error(`Unhandled element type ${element.type}`)})
export default function Page() { const [editor] = useState(() => { const basicEditor = withHistory(withReact(createEditor())) const cloudEditor = withCloud(basicEditor, { apiKey: "MY_API_KEY", }) CloudComponents.withEditor(cloudEditor) return cloudEditor })
return ( <Slate editor={editor} value={[{ type: "paragraph", children: [{ text: "Hello World" }] }]} > <input type="file" onChange={editor.cloud.handleInputFileChange} multiple /> <Editable renderElement={renderElement} onPaste={editor.cloud.handlePaste} onDrop={editor.cloud.handleDrop} /> </Slate> )}
When the user clicks the <input type="file" />
button, it opens a file picker, and when files are picked the upload process begins.
To programmatically upload a file from a File
object, use the editor.cloud.uploadFile
method and pass a File
object as the first argument.
Internally, the handlePaste
, handleDrop
and handleInputFileChange
methods all use the editor.cloud.uploadFile
method.
A good use case for this is if you programmatically generate File
objects, for example converting a Canvas
to an png
, and then you want to upload it.
// ✅ import `useCallback` for use laterimport { useCallback, useState } from "react"import { createEditor } from "slate"import { withHistory } from "slate-history"import { Editable, Slate, withReact } from "slate-react"import { withCloud } from "slate-cloud"import { CloudComponents } from "slate-cloud/cloud-components"
const renderElement = CloudComponents.withRenderElement((props) => { const { element } = props if (element.type === "paragraph") { return <p {...props.attributes}>{props.children}</p> } throw new Error(`Unhandled element type ${element.type}`)})
export default function Page() { const [editor] = useState(() => { const basicEditor = withHistory(withReact(createEditor())) const cloudEditor = withCloud(basicEditor, { apiKey: "MY_API_KEY", }) CloudComponents.withEditor(cloudEditor) return cloudEditor })
// ✅ This callback goes through each file and uploads it const upload = useCallback( (e) => { const files = e.target.files if (files == null || files.length === 0) return for (const file of files) { editor.cloud.uploadFile(file) } }, [editor] )
return ( <Slate editor={editor} value={[{ type: "paragraph", children: [{ text: "Hello World" }] }]} > {/* ✅ Add `upload` method as `onChange` handler */} <input type="file" onChange={upload} multiple /> <Editable renderElement={renderElement} onPaste={editor.cloud.handlePaste} onDrop={editor.cloud.handleDrop} /> </Slate> )}