1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-20 06:01:24 +02:00

update walkthroughs

This commit is contained in:
Ian Storm Taylor
2019-12-06 12:06:53 -05:00
parent 624c03339b
commit be8b7222ee
6 changed files with 370 additions and 99 deletions

View File

@@ -16,8 +16,6 @@ _Note, if you'd rather use a pre-bundled version of Slate, you can `yarn add sla
Once you've installed Slate, you'll need to import it. Once you've installed Slate, you'll need to import it.
Slate exposes a set of modules that you'll use to build your editor. The most important of which are the `Editor` class and the `<Editable>` component.
```js ```js
// Import the Slate editor factory. // Import the Slate editor factory.
import { createEditor } from 'slate' import { createEditor } from 'slate'
@@ -47,19 +45,44 @@ const App = () => {
Of course we haven't rendered anything, so you won't see any changes. Of course we haven't rendered anything, so you won't see any changes.
Next up is to render a `<Slate>` context provider. Next we want to create state for `value` and `selection`:
The provider component keeps track of your Slate editor, its plugins, its default value, and any changes that occur. It **must** be rendered above any `<Editable>` components. But it can also provide the editor state to other components like toolbars, menus, etc. using the `useSlate` hook.
```jsx ```jsx
const App = () => { const App = () => {
const editor = useMemo(() => withReact(createEditor()), []) const editor = useMemo(() => withReact(createEditor()), [])
// Render the Slate editor context.
return <Slate editor={editor} /> // Keep track of state for the value and selection of the editor.
const [value, setValue] = useState([])
const [selection, setSelection] = useState(null)
return null
} }
``` ```
You can think of the `<Slate>` component as provided an "un-controlled" editor context to every component underneath it. Next up is to render a `<Slate>` context provider.
The provider component keeps track of your Slate editor, its plugins, its value, its selection, and any changes that occur. It **must** be rendered above any `<Editable>` components. But it can also provide the editor state to other components like toolbars, menus, etc. using the `useSlate` hook.
```jsx
const App = () => {
const editor = useMemo(() => withReact(createEditor()), [])
const [value, setValue] = useState([])
const [selection, setSelection] = useState(null)
// Render the Slate context.
return (
<Slate
editor={editor}
value={value}
selection={selection}
onChange={(value, selection) => {
setValue(value)
setSelection(selection)
}}
/>
)
}
```
You can think of the `<Slate>` component as providing a "controlled" context to every component underneath it.
This is a slightly different mental model than things like `<input>` or `<textarea>`, because richtext documents are more complex. You'll often want to include toolbars, or live previews, or other complex components next to your editable content. This is a slightly different mental model than things like `<input>` or `<textarea>`, because richtext documents are more complex. You'll often want to include toolbars, or live previews, or other complex components next to your editable content.
@@ -70,9 +93,19 @@ Okay, so the next step is to render the `<Editable>` component itself:
```jsx ```jsx
const App = () => { const App = () => {
const editor = useMemo(() => withReact(createEditor()), []) const editor = useMemo(() => withReact(createEditor()), [])
const [value, setValue] = useState([])
const [selection, setSelection] = useState(null)
return ( return (
// Add the editable component inside the context. // Add the editable component inside the context.
<Slate editor={editor}> <Slate
editor={editor}
value={value}
selection={selection}
onChange={(value, selection) => {
setValue(value)
setSelection(selection)
}}
>
<Editable /> <Editable />
</Slate> </Slate>
) )
@@ -81,28 +114,32 @@ const App = () => {
The `<Editable>` component acts like `contenteditable`. Anywhere you render it will render an editable richtext document for the nearest editor context. The `<Editable>` component acts like `contenteditable`. Anywhere you render it will render an editable richtext document for the nearest editor context.
There's only one last step. So far we haven't defined what the default value of the editor is, so it's empty. Let's fix that by defining an initial value. There's only one last step. So far we've been using an empty `[]` array as the initial value of the editor, so it has no content. Let's fix that by defining an initial value.
The value is just plain JSON. Here's one containing a single paragraph block with some text in it: The value is just plain JSON. Here's one containing a single paragraph block with some text in it:
```js ```js
// Create our default value...
const defaultValue = [
{
type: 'paragraph',
children: [
{
text: 'A line of text in a paragraph.',
},
],
},
]
const App = () => { const App = () => {
const editor = useMemo(() => withReact(createEditor()), []) const editor = useMemo(() => withReact(createEditor()), [])
const [selection, setSelection] = useState(null)
// Add the initial value when setting up our state.
const [value, setValue] = useState([
{
type: 'paragraph',
children: [{ text: 'A line of text in a paragraph.' }],
},
])
return ( return (
// Add the default value as a prop to the editor context. <Slate
<Slate editor={editor} defaultValue={defaultValue}> editor={editor}
value={value}
selection={selection}
onChange={(value, selection) => {
setValue(value)
setSelection(selection)
}}
>
<Editable /> <Editable />
</Slate> </Slate>
) )
@@ -112,5 +149,3 @@ const App = () => {
There you have it! There you have it!
That's the most basic example of Slate. If you render that onto the page, you should see a paragraph with the text `A line of text in a paragraph.`. And when you type, you should see the text change! That's the most basic example of Slate. If you render that onto the page, you should see a paragraph with the text `A line of text in a paragraph.`. And when you type, you should see the text change!
You'll notice that there is no `onChange` handler defined. That's because the `<Slate>` context acts like an **un-controlled** component, with the changes automatically being propagated to any context consumers. However, just like with un-controlled components you can attach an `onChange` prop to listen for changes. We'll cover that later.

View File

@@ -11,8 +11,24 @@ Here's our app from earlier:
```js ```js
const App = () => { const App = () => {
const editor = useMemo(() => withReact(createEditor()), []) const editor = useMemo(() => withReact(createEditor()), [])
const [selection, setSelection] = useState(null)
const [value, setValue] = useState([
{
type: 'paragraph',
children: [{ text: 'A line of text in a paragraph.' }],
},
])
return ( return (
<Slate editor={editor} defaultValue={defaultValue}> <Slate
editor={editor}
value={value}
selection={selection}
onChange={(value, selection) => {
setValue(value)
setSelection(selection)
}}
>
<Editable /> <Editable />
</Slate> </Slate>
) )
@@ -24,8 +40,24 @@ Now we add an `onKeyDown` handler:
```js ```js
const App = () => { const App = () => {
const editor = useMemo(() => withReact(createEditor()), []) const editor = useMemo(() => withReact(createEditor()), [])
const [selection, setSelection] = useState(null)
const [value, setValue] = useState([
{
type: 'paragraph',
children: [{ text: 'A line of text in a paragraph.' }],
},
])
return ( return (
<Slate editor={editor} defaultValue={defaultValue}> <Slate
editor={editor}
value={value}
selection={selection}
onChange={(value, selection) => {
setValue(value)
setSelection(selection)
}}
>
<Editable <Editable
// Define a new handler which prints the key that was pressed. // Define a new handler which prints the key that was pressed.
onKeyDown={event => { onKeyDown={event => {
@@ -46,8 +78,24 @@ Our `onKeyDown` handler might look like this:
```js ```js
const App = () => { const App = () => {
const editor = useMemo(() => withReact(createEditor()), []) const editor = useMemo(() => withReact(createEditor()), [])
const [selection, setSelection] = useState(null)
const [value, setValue] = useState([
{
type: 'paragraph',
children: [{ text: 'A line of text in a paragraph.' }],
},
])
return ( return (
<Slate editor={editor} defaultValue={defaultValue}> <Slate
editor={editor}
value={value}
selection={selection}
onChange={(value, selection) => {
setValue(value)
setSelection(selection)
}}
>
<Editable <Editable
onKeyDown={event => { onKeyDown={event => {
if (event.key === '&') { if (event.key === '&') {

View File

@@ -9,8 +9,24 @@ We'll show you how. Let's start with our app from earlier:
```js ```js
const App = () => { const App = () => {
const editor = useMemo(() => withReact(createEditor()), []) const editor = useMemo(() => withReact(createEditor()), [])
const [selection, setSelection] = useState(null)
const [value, setValue] = useState([
{
type: 'paragraph',
children: [{ text: 'A line of text in a paragraph.' }],
},
])
return ( return (
<Slate editor={editor} defaultValue={defaultValue}> <Slate
editor={editor}
value={value}
selection={selection}
onChange={(value, selection) => {
setValue(value)
setSelection(selection)
}}
>
<Editable <Editable
onKeyDown={event => { onKeyDown={event => {
if (event.key === '&') { if (event.key === '&') {
@@ -60,6 +76,13 @@ Now, let's add that renderer to our `Editor`:
```js ```js
const App = () => { const App = () => {
const editor = useMemo(() => withReact(createEditor()), []) const editor = useMemo(() => withReact(createEditor()), [])
const [selection, setSelection] = useState(null)
const [value, setValue] = useState([
{
type: 'paragraph',
children: [{ text: 'A line of text in a paragraph.' }],
},
])
// Define a rendering function based on the element passed to `props`. We use // Define a rendering function based on the element passed to `props`. We use
// `useCallback` here to memoize the function for subsequent renders. // `useCallback` here to memoize the function for subsequent renders.
@@ -73,7 +96,15 @@ const App = () => {
}, []) }, [])
return ( return (
<Slate editor={editor} defaultValue={defaultValue}> <Slate
editor={editor}
value={value}
selection={selection}
onChange={(value, selection) => {
setValue(value)
setSelection(selection)
}}
>
<Editable <Editable
// Pass in the `renderElement` function. // Pass in the `renderElement` function.
renderElement={renderElement} renderElement={renderElement}
@@ -109,6 +140,14 @@ import { Editor } from 'slate'
const App = () => { const App = () => {
const editor = useMemo(() => withReact(createEditor()), []) const editor = useMemo(() => withReact(createEditor()), [])
const [selection, setSelection] = useState(null)
const [value, setValue] = useState([
{
type: 'paragraph',
children: [{ text: 'A line of text in a paragraph.' }],
},
])
const renderElement = useCallback(props => { const renderElement = useCallback(props => {
switch (props.element.type) { switch (props.element.type) {
case 'code': case 'code':
@@ -119,7 +158,15 @@ const App = () => {
}, []) }, [])
return ( return (
<Slate editor={editor} defaultValue={defaultValue}> <Slate
editor={editor}
value={value}
selection={selection}
onChange={(value, selection) => {
setValue(value)
setSelection(selection)
}}
>
<Editable <Editable
renderElement={renderElement} renderElement={renderElement}
onKeyDown={event => { onKeyDown={event => {
@@ -154,8 +201,15 @@ But we forgot one thing. When you hit `` Ctrl-` `` again, it should change the c
```js ```js
const App = () => { const App = () => {
const [value, setValue] = useState(initialValue)
const editor = useMemo(() => withReact(createEditor()), []) const editor = useMemo(() => withReact(createEditor()), [])
const [selection, setSelection] = useState(null)
const [value, setValue] = useState([
{
type: 'paragraph',
children: [{ text: 'A line of text in a paragraph.' }],
},
])
const renderElement = useCallback(props => { const renderElement = useCallback(props => {
switch (props.element.type) { switch (props.element.type) {
case 'code': case 'code':
@@ -166,20 +220,26 @@ const App = () => {
}, []) }, [])
return ( return (
<Slate editor={editor} defaultValue={defaultValue}> <Slate
editor={editor}
value={value}
selection={selection}
onChange={(value, selection) => {
setValue(value)
setSelection(selection)
}}
>
<Editable <Editable
renderElement={renderElement} renderElement={renderElement}
onKeyDown={event => { onKeyDown={event => {
if (event.key === '`' && event.ctrlKey) { if (event.key === '`' && event.ctrlKey) {
event.preventDefault() event.preventDefault()
// Determine whether any of the currently selected blocks are code blocks. // Determine whether any of the currently selected blocks are code blocks.
const [node] = Editor.nodes(editor, { match: { type: 'code' } }) const [match] = Editor.nodes(editor, { match: { type: 'code' } })
const isCodeActive = !!node // Toggle the block type depending on whether there's already a match.
// Toggle the block type depending on `isCode`.
Editor.setNodes( Editor.setNodes(
editor, editor,
{ type: isCodeActive ? 'paragraph' : 'code' }, { type: match ? 'paragraph' : 'code' },
{ match: 'block' } { match: 'block' }
) )
} }

View File

@@ -9,6 +9,14 @@ So we start with our app from earlier:
```js ```js
const App = () => { const App = () => {
const editor = useMemo(() => withReact(createEditor()), []) const editor = useMemo(() => withReact(createEditor()), [])
const [selection, setSelection] = useState(null)
const [value, setValue] = useState([
{
type: 'paragraph',
children: [{ text: 'A line of text in a paragraph.' }],
},
])
const renderElement = useCallback(props => { const renderElement = useCallback(props => {
switch (props.element.type) { switch (props.element.type) {
case 'code': case 'code':
@@ -19,18 +27,25 @@ const App = () => {
}, []) }, [])
return ( return (
<Slate editor={editor} defaultValue={defaultValue}> <Slate
editor={editor}
value={value}
selection={selection}
onChange={(value, selection) => {
setValue(value)
setSelection(selection)
}}
>
<Editable <Editable
renderElement={renderElement} renderElement={renderElement}
onKeyDown={event => { onKeyDown={event => {
if (event.key === '`' && event.ctrlKey) { if (event.key === '`' && event.ctrlKey) {
event.preventDefault() event.preventDefault()
const { selection } = editor const { selection } = editor
const [node] = Editor.nodes(editor, { match: { type: 'code' } }) const [match] = Editor.nodes(editor, { match: { type: 'code' } })
const isCodeActive = !!node
Editor.setNodes( Editor.setNodes(
editor, editor,
{ type: isCodeActive ? 'paragraph' : 'code' }, { type: match ? 'paragraph' : 'code' },
{ match: 'block' } { match: 'block' }
) )
} }
@@ -46,6 +61,14 @@ And now, we'll edit the `onKeyDown` handler to make it so that when you press `c
```js ```js
const App = () => { const App = () => {
const editor = useMemo(() => withReact(createEditor()), []) const editor = useMemo(() => withReact(createEditor()), [])
const [selection, setSelection] = useState(null)
const [value, setValue] = useState([
{
type: 'paragraph',
children: [{ text: 'A line of text in a paragraph.' }],
},
])
const renderElement = useCallback(props => { const renderElement = useCallback(props => {
switch (prop.element.type) { switch (prop.element.type) {
case 'code': case 'code':
@@ -56,7 +79,15 @@ const App = () => {
}, []) }, [])
return ( return (
<Slate editor={editor} defaultValue={defaultValue}> <Slate
editor={editor}
value={value}
selection={selection}
onChange={(value, selection) => {
setValue(value)
setSelection(selection)
}}
>
<Editable <Editable
renderElement={renderElement} renderElement={renderElement}
onKeyDown={event => { onKeyDown={event => {
@@ -68,11 +99,10 @@ const App = () => {
// When "`" is pressed, keep our existing code block logic. // When "`" is pressed, keep our existing code block logic.
case '`': { case '`': {
event.preventDefault() event.preventDefault()
const [node] = Editor.nodes(editor, { match: { type: 'code' } }) const [match] = Editor.nodes(editor, { match: { type: 'code' } })
const isCodeActive = !!node
Editor.setNodes( Editor.setNodes(
editor, editor,
{ type: isCodeActive ? null : 'code' }, { type: match ? 'paragraph' : 'code' },
{ match: 'block' } { match: 'block' }
) )
break break
@@ -123,6 +153,14 @@ And now, let's tell Slate about that leaf. To do that, we'll pass in the `render
```js ```js
const App = () => { const App = () => {
const editor = useMemo(() => withReact(createEditor()), []) const editor = useMemo(() => withReact(createEditor()), [])
const [selection, setSelection] = useState(null)
const [value, setValue] = useState([
{
type: 'paragraph',
children: [{ text: 'A line of text in a paragraph.' }],
},
])
const renderElement = useCallback(props => { const renderElement = useCallback(props => {
switch (props.element.type) { switch (props.element.type) {
case 'code': case 'code':
@@ -138,7 +176,15 @@ const App = () => {
}, []) }, [])
return ( return (
<Slate editor={editor} defaultValue={defaultValue}> <Slate
editor={editor}
value={value}
selection={selection}
onChange={(value, selection) => {
setValue(value)
setSelection(selection)
}}
>
<Editable <Editable
renderElement={renderElement} renderElement={renderElement}
// Pass in the `renderLeaf` function. // Pass in the `renderLeaf` function.
@@ -151,11 +197,10 @@ const App = () => {
switch (event.key) { switch (event.key) {
case '`': { case '`': {
event.preventDefault() event.preventDefault()
const [node] = Editor.nodes(editor, { match: { type: 'code' } }) const [match] = Editor.nodes(editor, { match: { type: 'code' } })
const isCodeActive = !!node
Editor.setNodes( Editor.setNodes(
editor, editor,
{ type: isCodeActive ? null : 'code' }, { type: match ? null : 'code' },
{ match: 'block' } { match: 'block' }
) )
break break

View File

@@ -13,6 +13,14 @@ We'll start with our app from earlier:
```js ```js
const App = () => { const App = () => {
const editor = useMemo(() => withReact(createEditor()), []) const editor = useMemo(() => withReact(createEditor()), [])
const [selection, setSelection] = useState(null)
const [value, setValue] = useState([
{
type: 'paragraph',
children: [{ text: 'A line of text in a paragraph.' }],
},
])
const renderElement = useCallback(props => { const renderElement = useCallback(props => {
switch (props.element.type) { switch (props.element.type) {
case 'code': case 'code':
@@ -27,7 +35,15 @@ const App = () => {
}, []) }, [])
return ( return (
<Slate editor={editor} defaultValue={defaultValue}> <Slate
editor={editor}
value={value}
selection={selection}
onChange={(value, selection) => {
setValue(value)
setSelection(selection)
}}
>
<Editable <Editable
renderElement={renderElement} renderElement={renderElement}
renderLeaf={renderLeaf} renderLeaf={renderLeaf}
@@ -39,11 +55,10 @@ const App = () => {
switch (event.key) { switch (event.key) {
case '`': { case '`': {
event.preventDefault() event.preventDefault()
const [node] = Editor.nodes(editor, { match: { type: 'code' } }) const [match] = Editor.nodes(editor, { match: { type: 'code' } })
const isCodeActive = !!node
Editor.setNodes( Editor.setNodes(
editor, editor,
{ type: isCodeActive ? null : 'code' }, { type: match ? null : 'code' },
{ match: 'block' } { match: 'block' }
) )
break break
@@ -79,6 +94,14 @@ const withCustom = editor => {
const App = () => { const App = () => {
// Wrap the editor with our new `withCustom` plugin. // Wrap the editor with our new `withCustom` plugin.
const editor = useMemo(() => withCustom(withReact(createEditor())), []) const editor = useMemo(() => withCustom(withReact(createEditor())), [])
const [selection, setSelection] = useState(null)
const [value, setValue] = useState([
{
type: 'paragraph',
children: [{ text: 'A line of text in a paragraph.' }],
},
])
const renderElement = useCallback(props => { const renderElement = useCallback(props => {
switch (props.element.type) { switch (props.element.type) {
case 'code': case 'code':
@@ -93,7 +116,15 @@ const App = () => {
}, []) }, [])
return ( return (
<Slate editor={editor} defaultValue={defaultValue}> <Slate
editor={editor}
value={value}
selection={selection}
onChange={(value, selection) => {
setValue(value)
setSelection(selection)
}}
>
<Editable <Editable
renderElement={renderElement} renderElement={renderElement}
renderLeaf={renderLeaf} renderLeaf={renderLeaf}
@@ -193,6 +224,14 @@ const CustomEditor = {
const App = () => { const App = () => {
const editor = useMemo(() => withCustom(withReact(createEditor())), []) const editor = useMemo(() => withCustom(withReact(createEditor())), [])
const [selection, setSelection] = useState(null)
const [value, setValue] = useState([
{
type: 'paragraph',
children: [{ text: 'A line of text in a paragraph.' }],
},
])
const renderElement = useCallback(props => { const renderElement = useCallback(props => {
switch (props.element.type) { switch (props.element.type) {
case 'code': case 'code':
@@ -207,16 +246,24 @@ const App = () => {
}, []) }, [])
return ( return (
<Slate editor={editor} defaultValue={defaultValue}> <Slate
editor={editor}
value={value}
selection={selection}
onChange={(value, selection) => {
setValue(value)
setSelection(selection)
}}
>
<Editable <Editable
renderElement={renderElement} renderElement={renderElement}
renderLeaf={renderLeaf} renderLeaf={renderLeaf}
// Replace the `onKeyDown` logic with our new commands.
onKeyDown={event => { onKeyDown={event => {
if (!event.ctrlKey) { if (!event.ctrlKey) {
return return
} }
// Replace the `onKeyDown` logic with our new commands.
switch (event.key) { switch (event.key) {
case '`': { case '`': {
event.preventDefault() event.preventDefault()
@@ -242,6 +289,14 @@ Now our commands are clearly defined and you can invoke them from anywhere we ha
```js ```js
const App = () => { const App = () => {
const editor = useMemo(() => withCustom(withReact(createEditor())), []) const editor = useMemo(() => withCustom(withReact(createEditor())), [])
const [selection, setSelection] = useState(null)
const [value, setValue] = useState([
{
type: 'paragraph',
children: [{ text: 'A line of text in a paragraph.' }],
},
])
const renderElement = useCallback(props => { const renderElement = useCallback(props => {
switch (props.element.type) { switch (props.element.type) {
case 'code': case 'code':
@@ -256,8 +311,16 @@ const App = () => {
}, []) }, [])
return ( return (
// Add a toolbar with buttons that call the same methods. // Add a toolbar with buttons that call the same methods.
<Slate editor={editor} defaultValue={defaultValue}> <Slate
editor={editor}
value={value}
selection={selection}
onChange={(value, selection) => {
setValue(value)
setSelection(selection)
}}
>
<div> <div>
<button <button
onMouseDown={event => { onMouseDown={event => {

View File

@@ -7,24 +7,26 @@ In this guide, we'll show you how to add logic to save your Slate content to a d
Let's start with a basic editor: Let's start with a basic editor:
```js ```js
import React, { useMemo } from 'react'
import { createEditor } from 'slate'
import { Slate, Editable, withReact } from 'slate-react'
const defaultValue = [
{
children: [
{
text: 'A line of text in a paragraph.',
},
],
},
]
const App = () => { const App = () => {
const editor = useMemo(() => withReact(createEditor()), []) const editor = useMemo(() => withReact(createEditor()), [])
const [selection, setSelection] = useState(null)
const [value, setValue] = useState([
{
type: 'paragraph',
children: [{ text: 'A line of text in a paragraph.' }],
},
])
return ( return (
<Slate editor={editor} defaultValue={defaultValue}> <Slate
editor={editor}
value={value}
selection={selection}
onChange={(value, selection) => {
setValue(value)
setSelection(selection)
}}
>
<Editable /> <Editable />
</Slate> </Slate>
) )
@@ -50,11 +52,23 @@ const defaultValue = [
const App = () => { const App = () => {
const editor = useMemo(() => withReact(createEditor()), []) const editor = useMemo(() => withReact(createEditor()), [])
const [selection, setSelection] = useState(null)
const [value, setValue] = useState([
{
type: 'paragraph',
children: [{ text: 'A line of text in a paragraph.' }],
},
])
return ( return (
<Slate <Slate
editor={editor} editor={editor}
defaultValue={defaultValue} value={value}
onChange={value => { selection={selection}
onChange={(value, selection) => {
setValue(value)
setSelection(selection)
// Save the value to Local Storage. // Save the value to Local Storage.
const content = JSON.stringify(value) const content = JSON.stringify(value)
localStorage.setItem('content', content) localStorage.setItem('content', content)
@@ -71,25 +85,27 @@ Now whenever you edit the page, if you look in Local Storage, you should see the
But... if you refresh the page, everything is still reset. That's because we need to make sure the initial value is pulled from that same Local Storage location, like so: But... if you refresh the page, everything is still reset. That's because we need to make sure the initial value is pulled from that same Local Storage location, like so:
```js ```js
// Update the initial content to be pulled from Local Storage if it exists.
const existingValue = JSON.parse(localStorage.getItem('content'))
const defaultValue = existingValue || [
{
children: [
{
text: 'A line of text in a paragraph.',
},
],
},
]
const App = () => { const App = () => {
const editor = useMemo(() => withReact(createEditor()), []) const editor = useMemo(() => withReact(createEditor()), [])
const [selection, setSelection] = useState(null)
// Update the initial content to be pulled from Local Storage if it exists.
const [value, setValue] = useState(
JSON.parse(localStorage.getItem('content')) || [
{
type: 'paragraph',
children: [{ text: 'A line of text in a paragraph.' }],
},
]
)
return ( return (
<Slate <Slate
editor={editor} editor={editor}
defaultValue={defaultValue} value={value}
onChange={value => { selection={selection}
onChange={(value, selection) => {
setValue(value)
setSelection(selection)
const content = JSON.stringify(value) const content = JSON.stringify(value)
localStorage.setItem('content', content) localStorage.setItem('content', content)
}} }}
@@ -131,20 +147,24 @@ const deserialize = string => {
}) })
} }
// Use our deserializing function to read the data from Local Storage.
const existingValue = localStorage.getItem('content')
const initialValue = deserialize(existingValue || '')
const App = () => { const App = () => {
const editor = useMemo(() => withReact(createEditor()), []) const editor = useMemo(() => withReact(createEditor()), [])
const [selection, setSelection] = useState(null)
// Use our deserializing function to read the data from Local Storage.
const [value, setValue] = useState(
deserialize(localStorage.getItem('content')) || ''
)
return ( return (
<Slate <Slate
editor={editor} editor={editor}
defaultValue={defaultValue} value={value}
onChange={value => { selection={selection}
onChange={(value, selection) => {
setValue(value)
setSelection(selection)
// Serialize the value and save the string value to Local Storage. // Serialize the value and save the string value to Local Storage.
const content = serialize(value) localStorage.setItem('content', serialize(value))
localStorage.setItem('content', content)
}} }}
> >
<Editable /> <Editable />