mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-14 03:03:58 +02:00
Make onChange prop optional, update examples and docs to treat slate as uncontrolled (#4922)
* Make onChange prop optional, update examples and docs to treat slate as uncontrolled * Add changeset
This commit is contained in:
5
.changeset/red-bottles-peel.md
Normal file
5
.changeset/red-bottles-peel.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'slate-react': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Make Slate component onChange optional
|
@@ -66,53 +66,23 @@ declare module 'slate' {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Also you must annotate `useState<Descendant[]>` and the editor's initial value.
|
|
||||||
const App = () => {
|
|
||||||
const initialValue: CustomElement[] = []
|
|
||||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
|
||||||
return (
|
|
||||||
<Slate value={value} onChange={setValue}>
|
|
||||||
...
|
|
||||||
</Slate>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Next we want to create state for `value`:
|
|
||||||
|
|
||||||
```jsx
|
|
||||||
const App = () => {
|
|
||||||
const [editor] = useState(() => withReact(createEditor()))
|
|
||||||
|
|
||||||
// Keep track of state for the value of the editor.
|
|
||||||
const [value, setValue] = useState([])
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Next up is to render a `<Slate>` context provider.
|
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.
|
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
|
```jsx
|
||||||
|
const initialValue = []
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
const [editor] = useState(() => withReact(createEditor()))
|
const [editor] = useState(() => withReact(createEditor()))
|
||||||
const [value, setValue] = useState([])
|
|
||||||
// Render the Slate context.
|
// Render the Slate context.
|
||||||
return (
|
return <Slate editor={editor} value={initialValue} />
|
||||||
<Slate
|
|
||||||
editor={editor}
|
|
||||||
value={value}
|
|
||||||
onChange={newValue => setValue(newValue)}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
You can think of the `<Slate>` component as providing a context to every component underneath it.
|
You can think of the `<Slate>` component as providing a context to every component underneath it.
|
||||||
|
|
||||||
> As of v0.67 the Slate Provider's "value" prop is now only used as initial state for editor.children. If your code relies on replacing editor.children you should do so by replacing it directly instead of relying on the "value" prop to do this for you. See [Slate PR 4540](https://github.com/ianstormtaylor/slate/pull/4540) for a more in-depth discussion.
|
> Slate Provider's "value" prop is only used as initial state for editor.children. If your code relies on replacing editor.children you should do so by replacing it directly instead of relying on the "value" prop to do this for you. See [Slate PR 4540](https://github.com/ianstormtaylor/slate/pull/4540) for a more in-depth discussion.
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
@@ -121,16 +91,14 @@ By having a shared context, those other components can execute commands, query t
|
|||||||
Okay, so the next step is to render the `<Editable>` component itself:
|
Okay, so the next step is to render the `<Editable>` component itself:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
|
const initialValue = []
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
const [editor] = useState(() => withReact(createEditor()))
|
const [editor] = useState(() => withReact(createEditor()))
|
||||||
const [value, setValue] = useState([])
|
const [value, setValue] = useState([])
|
||||||
return (
|
return (
|
||||||
// Add the editable component inside the context.
|
// Add the editable component inside the context.
|
||||||
<Slate
|
<Slate editor={editor} value={initialValue}>
|
||||||
editor={editor}
|
|
||||||
value={value}
|
|
||||||
onChange={newValue => setValue(newValue)}
|
|
||||||
>
|
|
||||||
<Editable />
|
<Editable />
|
||||||
</Slate>
|
</Slate>
|
||||||
)
|
)
|
||||||
@@ -144,22 +112,20 @@ There's only one last step. So far we've been using an empty `[]` array as the i
|
|||||||
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:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
|
// Add the initial value.
|
||||||
|
const initialValue = [
|
||||||
|
{
|
||||||
|
type: 'paragraph',
|
||||||
|
children: [{ text: 'A line of text in a paragraph.' }],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
const [editor] = useState(() => withReact(createEditor()))
|
const [editor] = useState(() => withReact(createEditor())
|
||||||
// Add the initial value when setting up our state.
|
const [value, setValue] = useState()
|
||||||
const [value, setValue] = useState([
|
|
||||||
{
|
|
||||||
type: 'paragraph',
|
|
||||||
children: [{ text: 'A line of text in a paragraph.' }],
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slate
|
<Slate editor={editor} value={initialValue}>
|
||||||
editor={editor}
|
|
||||||
value={value}
|
|
||||||
onChange={newValue => setValue(newValue)}
|
|
||||||
>
|
|
||||||
<Editable />
|
<Editable />
|
||||||
</Slate>
|
</Slate>
|
||||||
)
|
)
|
||||||
|
@@ -9,17 +9,18 @@ Let's use the `onKeyDown` handler to change the editor's content when we press a
|
|||||||
Here's our app from earlier:
|
Here's our app from earlier:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
|
const initialValue = [
|
||||||
|
{
|
||||||
|
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 [value, setValue] = useState([
|
|
||||||
{
|
|
||||||
type: 'paragraph',
|
|
||||||
children: [{ text: 'A line of text in a paragraph.' }],
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<Editable />
|
<Editable />
|
||||||
</Slate>
|
</Slate>
|
||||||
)
|
)
|
||||||
@@ -29,17 +30,18 @@ const App = () => {
|
|||||||
Now we add an `onKeyDown` handler:
|
Now we add an `onKeyDown` handler:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
|
const initialValue = [
|
||||||
|
{
|
||||||
|
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 [value, setValue] = useState([
|
|
||||||
{
|
|
||||||
type: 'paragraph',
|
|
||||||
children: [{ text: 'A line of text in a paragraph.' }],
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<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 => {
|
||||||
@@ -58,17 +60,18 @@ Now we want to make it actually change the content. For the purposes of our exam
|
|||||||
Our `onKeyDown` handler might look like this:
|
Our `onKeyDown` handler might look like this:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
|
const initialValue = [
|
||||||
|
{
|
||||||
|
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 [value, setValue] = useState([
|
|
||||||
{
|
|
||||||
type: 'paragraph',
|
|
||||||
children: [{ text: 'A line of text in a paragraph.' }],
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<Editable
|
<Editable
|
||||||
onKeyDown={event => {
|
onKeyDown={event => {
|
||||||
if (event.key === '&') {
|
if (event.key === '&') {
|
||||||
|
@@ -7,17 +7,18 @@ But that's not all you can do. Slate lets you define any type of custom blocks y
|
|||||||
We'll show you how. Let's start with our app from earlier:
|
We'll show you how. Let's start with our app from earlier:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
|
const initialValue = [
|
||||||
|
{
|
||||||
|
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 [value, setValue] = useState([
|
|
||||||
{
|
|
||||||
type: 'paragraph',
|
|
||||||
children: [{ text: 'A line of text in a paragraph.' }],
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<Editable
|
<Editable
|
||||||
onKeyDown={event => {
|
onKeyDown={event => {
|
||||||
if (event.key === '&') {
|
if (event.key === '&') {
|
||||||
@@ -65,14 +66,15 @@ const DefaultElement = props => {
|
|||||||
Now, let's add that renderer to our `Editor`:
|
Now, let's add that renderer to our `Editor`:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
|
const initialValue = [
|
||||||
|
{
|
||||||
|
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 [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.
|
||||||
@@ -86,7 +88,7 @@ const App = () => {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<Editable
|
<Editable
|
||||||
// Pass in the `renderElement` function.
|
// Pass in the `renderElement` function.
|
||||||
renderElement={renderElement}
|
renderElement={renderElement}
|
||||||
@@ -120,14 +122,15 @@ Okay, but now we'll need a way for the user to actually turn a block into a code
|
|||||||
// Import the `Editor` and `Transforms` helpers from Slate.
|
// Import the `Editor` and `Transforms` helpers from Slate.
|
||||||
import { Editor, Transforms } from 'slate'
|
import { Editor, Transforms } from 'slate'
|
||||||
|
|
||||||
|
const initialValue = [
|
||||||
|
{
|
||||||
|
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 [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) {
|
||||||
@@ -139,7 +142,7 @@ const App = () => {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<Editable
|
<Editable
|
||||||
renderElement={renderElement}
|
renderElement={renderElement}
|
||||||
onKeyDown={event => {
|
onKeyDown={event => {
|
||||||
@@ -177,14 +180,15 @@ Now, if you press ``Ctrl-``` the block your cursor is in should turn into a code
|
|||||||
But we forgot one thing. When you hit ``Ctrl-``` again, it should change the code block back into a paragraph. To do that, we'll need to add a bit of logic to change the type we set based on whether any of the currently selected blocks are already a code block:
|
But we forgot one thing. When you hit ``Ctrl-``` again, it should change the code block back into a paragraph. To do that, we'll need to add a bit of logic to change the type we set based on whether any of the currently selected blocks are already a code block:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
|
const initialValue = [
|
||||||
|
{
|
||||||
|
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 [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) {
|
||||||
@@ -196,7 +200,7 @@ const App = () => {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<Editable
|
<Editable
|
||||||
renderElement={renderElement}
|
renderElement={renderElement}
|
||||||
onKeyDown={event => {
|
onKeyDown={event => {
|
||||||
|
@@ -7,26 +7,27 @@ In this guide, we'll show you how to add custom formatting options, like **bold*
|
|||||||
So we start with our app from earlier:
|
So we start with our app from earlier:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
const renderElement = (props) => {
|
const renderElement = props => {
|
||||||
switch (props.element.type) {
|
switch (props.element.type) {
|
||||||
case 'code':
|
case 'code':
|
||||||
return <CodeElement {...props} />
|
return <CodeElement {...props} />
|
||||||
default:
|
default:
|
||||||
return <DefaultElement {...props} />
|
return <DefaultElement {...props} />
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
|
const initialValue = [
|
||||||
|
{
|
||||||
|
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 [value, setValue] = useState([
|
|
||||||
{
|
|
||||||
type: 'paragraph',
|
|
||||||
children: [{ text: 'A line of text in a paragraph.' }],
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<Editable
|
<Editable
|
||||||
renderElement={renderElement}
|
renderElement={renderElement}
|
||||||
onKeyDown={event => {
|
onKeyDown={event => {
|
||||||
@@ -52,14 +53,15 @@ const App = () => {
|
|||||||
And now, we'll edit the `onKeyDown` handler to make it so that when you press `control-B`, it will add a `bold` format to the currently selected text:
|
And now, we'll edit the `onKeyDown` handler to make it so that when you press `control-B`, it will add a `bold` format to the currently selected text:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
|
const initialValue = [
|
||||||
|
{
|
||||||
|
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 [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) {
|
||||||
@@ -71,7 +73,7 @@ const App = () => {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={value}>
|
||||||
<Editable
|
<Editable
|
||||||
renderElement={renderElement}
|
renderElement={renderElement}
|
||||||
onKeyDown={event => {
|
onKeyDown={event => {
|
||||||
@@ -137,14 +139,15 @@ Pretty familiar, right?
|
|||||||
And now, let's tell Slate about that leaf. To do that, we'll pass in the `renderLeaf` prop to our editor.
|
And now, let's tell Slate about that leaf. To do that, we'll pass in the `renderLeaf` prop to our editor.
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
|
const initialValue = [
|
||||||
|
{
|
||||||
|
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 [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) {
|
||||||
@@ -161,7 +164,7 @@ const App = () => {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<Editable
|
<Editable
|
||||||
renderElement={renderElement}
|
renderElement={renderElement}
|
||||||
// Pass in the `renderLeaf` function.
|
// Pass in the `renderLeaf` function.
|
||||||
|
@@ -11,14 +11,15 @@ Let's see how this works.
|
|||||||
We'll start with our app from earlier:
|
We'll start with our app from earlier:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
|
const initialValue = [
|
||||||
|
{
|
||||||
|
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 [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) {
|
||||||
@@ -34,7 +35,7 @@ const App = () => {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<Editable
|
<Editable
|
||||||
renderElement={renderElement}
|
renderElement={renderElement}
|
||||||
renderLeaf={renderLeaf}
|
renderLeaf={renderLeaf}
|
||||||
@@ -117,14 +118,15 @@ const CustomEditor = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const initialValue = [
|
||||||
|
{
|
||||||
|
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 [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) {
|
||||||
@@ -140,7 +142,7 @@ const App = () => {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<Editable
|
<Editable
|
||||||
renderElement={renderElement}
|
renderElement={renderElement}
|
||||||
renderLeaf={renderLeaf}
|
renderLeaf={renderLeaf}
|
||||||
@@ -173,14 +175,15 @@ const App = () => {
|
|||||||
Now our commands are clearly defined and you can invoke them from anywhere we have access to our `editor` object. For example, from hypothetical toolbar buttons:
|
Now our commands are clearly defined and you can invoke them from anywhere we have access to our `editor` object. For example, from hypothetical toolbar buttons:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
|
const initialValue = [
|
||||||
|
{
|
||||||
|
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 [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) {
|
||||||
@@ -197,7 +200,7 @@ 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} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button
|
||||||
onMouseDown={event => {
|
onMouseDown={event => {
|
||||||
|
@@ -7,17 +7,18 @@ 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:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
|
const initialValue = [
|
||||||
|
{
|
||||||
|
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 [value, setValue] = useState([
|
|
||||||
{
|
|
||||||
type: 'paragraph',
|
|
||||||
children: [{ text: 'A line of text in a paragraph.' }],
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<Editable />
|
<Editable />
|
||||||
</Slate>
|
</Slate>
|
||||||
)
|
)
|
||||||
@@ -31,22 +32,21 @@ What we need to do is save the changes you make somewhere. For this example, we'
|
|||||||
So, in our `onChange` handler, we need to save the `value` if anything besides the selection was changed:
|
So, in our `onChange` handler, we need to save the `value` if anything besides the selection was changed:
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
|
const initialValue = [
|
||||||
|
{
|
||||||
|
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 [value, setValue] = useState([
|
|
||||||
{
|
|
||||||
type: 'paragraph',
|
|
||||||
children: [{ text: 'A line of text in a paragraph.' }],
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slate
|
<Slate
|
||||||
editor={editor}
|
editor={editor}
|
||||||
value={value}
|
value={initialValue}
|
||||||
onChange={value => {
|
onChange={value => {
|
||||||
setValue(value)
|
|
||||||
|
|
||||||
const isAstChange = editor.operations.some(
|
const isAstChange = editor.operations.some(
|
||||||
op => 'set_selection' !== op.type
|
op => 'set_selection' !== op.type
|
||||||
)
|
)
|
||||||
@@ -71,21 +71,21 @@ But... if you refresh the page, everything is still reset. That's because we nee
|
|||||||
const App = () => {
|
const App = () => {
|
||||||
const editor = useMemo(() => withReact(createEditor()), [])
|
const editor = useMemo(() => withReact(createEditor()), [])
|
||||||
// Update the initial content to be pulled from Local Storage if it exists.
|
// Update the initial content to be pulled from Local Storage if it exists.
|
||||||
const [value, setValue] = useState(
|
const initialValue = useMemo(
|
||||||
JSON.parse(localStorage.getItem('content')) || [
|
JSON.parse(localStorage.getItem('content')) || [
|
||||||
{
|
{
|
||||||
type: 'paragraph',
|
type: 'paragraph',
|
||||||
children: [{ text: 'A line of text in a paragraph.' }],
|
children: [{ text: 'A line of text in a paragraph.' }],
|
||||||
},
|
},
|
||||||
]
|
],
|
||||||
|
[]
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slate
|
<Slate
|
||||||
editor={editor}
|
editor={editor}
|
||||||
value={value}
|
value={initialValue}
|
||||||
onChange={value => {
|
onChange={value => {
|
||||||
setValue(value)
|
|
||||||
const isAstChange = editor.operations.some(
|
const isAstChange = editor.operations.some(
|
||||||
op => 'set_selection' !== op.type
|
op => 'set_selection' !== op.type
|
||||||
)
|
)
|
||||||
@@ -136,16 +136,16 @@ const deserialize = string => {
|
|||||||
const App = () => {
|
const App = () => {
|
||||||
const editor = useMemo(() => withReact(createEditor()), [])
|
const editor = useMemo(() => withReact(createEditor()), [])
|
||||||
// Use our deserializing function to read the data from Local Storage.
|
// Use our deserializing function to read the data from Local Storage.
|
||||||
const [value, setValue] = useState(
|
const initialValue = useMemo(
|
||||||
deserialize(localStorage.getItem('content')) || ''
|
deserialize(localStorage.getItem('content')) || '',
|
||||||
|
[]
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slate
|
<Slate
|
||||||
editor={editor}
|
editor={editor}
|
||||||
value={value}
|
value={initialValue}
|
||||||
onChange={value => {
|
onChange={value => {
|
||||||
setValue(value)
|
|
||||||
const isAstChange = editor.operations.some(
|
const isAstChange = editor.operations.some(
|
||||||
op => 'set_selection' !== op.type
|
op => 'set_selection' !== op.type
|
||||||
)
|
)
|
||||||
@@ -167,7 +167,7 @@ You can emulate this strategy for any format you like. You can serialize to HTML
|
|||||||
|
|
||||||
> 🤖 Note that even though you _can_ serialize your content however you like, there are tradeoffs. The serialization process has a cost itself, and certain formats may be harder to work with than others. In general we recommend writing your own format only if your use case has a specific need for it. Otherwise, you're often better leaving the data in the format Slate uses.
|
> 🤖 Note that even though you _can_ serialize your content however you like, there are tradeoffs. The serialization process has a cost itself, and certain formats may be harder to work with than others. In general we recommend writing your own format only if your use case has a specific need for it. Otherwise, you're often better leaving the data in the format Slate uses.
|
||||||
|
|
||||||
If you want to update the editor's content in response to events from outside of slate, you need to change the children property directly. The simplest way is to replace the value of editor.children `editor.children = newValue` and trigger a re-rendering (e.g. by calling `setValue(newValue)` in the example above). Alternatively, you can use slate's internal operations to transform the value, for example:
|
If you want to update the editor's content in response to events from outside of slate, you need to change the children property directly. The simplest way is to replace the value of editor.children `editor.children = newValue` and trigger a re-rendering (e.g. by calling `editor.onChange()` in the example above). Alternatively, you can use slate's internal operations to transform the value, for example:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
/**
|
/**
|
||||||
|
@@ -20,7 +20,7 @@ export const Slate = (props: {
|
|||||||
editor: ReactEditor
|
editor: ReactEditor
|
||||||
value: Descendant[]
|
value: Descendant[]
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
onChange: (value: Descendant[]) => void
|
onChange?: (value: Descendant[]) => void
|
||||||
}) => {
|
}) => {
|
||||||
const { editor, children, onChange, value, ...rest } = props
|
const { editor, children, onChange, value, ...rest } = props
|
||||||
const unmountRef = useRef(false)
|
const unmountRef = useRef(false)
|
||||||
@@ -48,7 +48,10 @@ export const Slate = (props: {
|
|||||||
} = getSelectorContext(editor)
|
} = getSelectorContext(editor)
|
||||||
|
|
||||||
const onContextChange = useCallback(() => {
|
const onContextChange = useCallback(() => {
|
||||||
onChange(editor.children)
|
if (onChange) {
|
||||||
|
onChange(editor.children)
|
||||||
|
}
|
||||||
|
|
||||||
setContext([editor])
|
setContext([editor])
|
||||||
handleSelectorChange(editor)
|
handleSelectorChange(editor)
|
||||||
}, [onChange])
|
}, [onChange])
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useMemo, useCallback } from 'react'
|
import React, { useMemo, useCallback } from 'react'
|
||||||
import {
|
import {
|
||||||
Slate,
|
Slate,
|
||||||
Editable,
|
Editable,
|
||||||
@@ -66,7 +66,6 @@ const initialValue: Descendant[] = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
const CheckListsExample = () => {
|
const CheckListsExample = () => {
|
||||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
|
||||||
const renderElement = useCallback(props => <Element {...props} />, [])
|
const renderElement = useCallback(props => <Element {...props} />, [])
|
||||||
const editor = useMemo(
|
const editor = useMemo(
|
||||||
() => withChecklists(withHistory(withReact(createEditor()))),
|
() => withChecklists(withHistory(withReact(createEditor()))),
|
||||||
@@ -74,7 +73,7 @@ const CheckListsExample = () => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<Editable
|
<Editable
|
||||||
renderElement={renderElement}
|
renderElement={renderElement}
|
||||||
placeholder="Get to work…"
|
placeholder="Get to work…"
|
||||||
|
@@ -10,7 +10,6 @@ import { withHistory } from 'slate-history'
|
|||||||
import { css } from '@emotion/css'
|
import { css } from '@emotion/css'
|
||||||
|
|
||||||
const CodeHighlightingExample = () => {
|
const CodeHighlightingExample = () => {
|
||||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
|
||||||
const [language, setLanguage] = useState('html')
|
const [language, setLanguage] = useState('html')
|
||||||
const renderLeaf = useCallback(props => <Leaf {...props} />, [])
|
const renderLeaf = useCallback(props => <Leaf {...props} />, [])
|
||||||
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
||||||
@@ -46,7 +45,7 @@ const CodeHighlightingExample = () => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<div
|
<div
|
||||||
contentEditable={false}
|
contentEditable={false}
|
||||||
style={{ position: 'relative', top: '5px', right: '5px' }}
|
style={{ position: 'relative', top: '5px', right: '5px' }}
|
||||||
|
@@ -1,13 +1,19 @@
|
|||||||
import React, { useState, useMemo } from 'react'
|
import React, { useMemo } from 'react'
|
||||||
import { createEditor, Descendant } from 'slate'
|
import { createEditor, Descendant } from 'slate'
|
||||||
import { Slate, Editable, withReact } from 'slate-react'
|
import { Slate, Editable, withReact } from 'slate-react'
|
||||||
import { withHistory } from 'slate-history'
|
import { withHistory } from 'slate-history'
|
||||||
|
|
||||||
|
const initialValue: Descendant[] = [
|
||||||
|
{
|
||||||
|
type: 'paragraph',
|
||||||
|
children: [{ text: '' }],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
const PlainTextExample = () => {
|
const PlainTextExample = () => {
|
||||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
|
||||||
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<Editable
|
<Editable
|
||||||
placeholder="Type something"
|
placeholder="Type something"
|
||||||
renderPlaceholder={({ children, attributes }) => (
|
renderPlaceholder={({ children, attributes }) => (
|
||||||
@@ -24,11 +30,4 @@ const PlainTextExample = () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialValue: Descendant[] = [
|
|
||||||
{
|
|
||||||
type: 'paragraph',
|
|
||||||
children: [{ text: '' }],
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
export default PlainTextExample
|
export default PlainTextExample
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useMemo } from 'react'
|
import React, { useMemo } from 'react'
|
||||||
import {
|
import {
|
||||||
Transforms,
|
Transforms,
|
||||||
createEditor,
|
createEditor,
|
||||||
@@ -14,10 +14,9 @@ import {
|
|||||||
} from 'slate-react'
|
} from 'slate-react'
|
||||||
|
|
||||||
const EmbedsExample = () => {
|
const EmbedsExample = () => {
|
||||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
|
||||||
const editor = useMemo(() => withEmbeds(withReact(createEditor())), [])
|
const editor = useMemo(() => withEmbeds(withReact(createEditor())), [])
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<Editable
|
<Editable
|
||||||
renderElement={props => <Element {...props} />}
|
renderElement={props => <Element {...props} />}
|
||||||
placeholder="Enter some text..."
|
placeholder="Enter some text..."
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useCallback, useMemo } from 'react'
|
import React, { useCallback, useMemo } from 'react'
|
||||||
import { Slate, Editable, withReact } from 'slate-react'
|
import { Slate, Editable, withReact } from 'slate-react'
|
||||||
import {
|
import {
|
||||||
Transforms,
|
Transforms,
|
||||||
@@ -64,14 +64,13 @@ const withLayout = editor => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ForcedLayoutExample = () => {
|
const ForcedLayoutExample = () => {
|
||||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
|
||||||
const renderElement = useCallback(props => <Element {...props} />, [])
|
const renderElement = useCallback(props => <Element {...props} />, [])
|
||||||
const editor = useMemo(
|
const editor = useMemo(
|
||||||
() => withLayout(withHistory(withReact(createEditor()))),
|
() => withLayout(withHistory(withReact(createEditor()))),
|
||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<Editable
|
<Editable
|
||||||
renderElement={renderElement}
|
renderElement={renderElement}
|
||||||
placeholder="Enter a title…"
|
placeholder="Enter a title…"
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useMemo, useRef, useEffect } from 'react'
|
import React, { useMemo, useRef, useEffect } from 'react'
|
||||||
import { Slate, Editable, withReact, useSlate, useFocused } from 'slate-react'
|
import { Slate, Editable, withReact, useSlate, useFocused } from 'slate-react'
|
||||||
import {
|
import {
|
||||||
Editor,
|
Editor,
|
||||||
@@ -14,11 +14,10 @@ import { withHistory } from 'slate-history'
|
|||||||
import { Button, Icon, Menu, Portal } from '../components'
|
import { Button, Icon, Menu, Portal } from '../components'
|
||||||
|
|
||||||
const HoveringMenuExample = () => {
|
const HoveringMenuExample = () => {
|
||||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
|
||||||
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<HoveringToolbar />
|
<HoveringToolbar />
|
||||||
<Editable
|
<Editable
|
||||||
renderLeaf={props => <Leaf {...props} />}
|
renderLeaf={props => <Leaf {...props} />}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useMemo, useCallback } from 'react'
|
import React, { useMemo, useCallback } from 'react'
|
||||||
import faker from 'faker'
|
import faker from 'faker'
|
||||||
import { createEditor, Descendant } from 'slate'
|
import { createEditor, Descendant } from 'slate'
|
||||||
import { Slate, Editable, withReact } from 'slate-react'
|
import { Slate, Editable, withReact } from 'slate-react'
|
||||||
@@ -22,11 +22,10 @@ for (let h = 0; h < HEADINGS; h++) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const HugeDocumentExample = () => {
|
const HugeDocumentExample = () => {
|
||||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
|
||||||
const renderElement = useCallback(props => <Element {...props} />, [])
|
const renderElement = useCallback(props => <Element {...props} />, [])
|
||||||
const editor = useMemo(() => withReact(createEditor()), [])
|
const editor = useMemo(() => withReact(createEditor()), [])
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<Editable renderElement={renderElement} spellCheck autoFocus />
|
<Editable renderElement={renderElement} spellCheck autoFocus />
|
||||||
</Slate>
|
</Slate>
|
||||||
)
|
)
|
||||||
|
@@ -15,7 +15,6 @@ const HOTKEYS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const IFrameExample = () => {
|
const IFrameExample = () => {
|
||||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
|
||||||
const renderElement = useCallback(
|
const renderElement = useCallback(
|
||||||
({ attributes, children }) => <p {...attributes}>{children}</p>,
|
({ attributes, children }) => <p {...attributes}>{children}</p>,
|
||||||
[]
|
[]
|
||||||
@@ -26,7 +25,7 @@ const IFrameExample = () => {
|
|||||||
const handleBlur = useCallback(() => ReactEditor.deselect(editor), [editor])
|
const handleBlur = useCallback(() => ReactEditor.deselect(editor), [editor])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
<MarkButton format="bold" icon="format_bold" />
|
<MarkButton format="bold" icon="format_bold" />
|
||||||
<MarkButton format="italic" icon="format_italic" />
|
<MarkButton format="italic" icon="format_italic" />
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useMemo } from 'react'
|
import React, { useMemo } from 'react'
|
||||||
import imageExtensions from 'image-extensions'
|
import imageExtensions from 'image-extensions'
|
||||||
import isUrl from 'is-url'
|
import isUrl from 'is-url'
|
||||||
import { Transforms, createEditor, Descendant } from 'slate'
|
import { Transforms, createEditor, Descendant } from 'slate'
|
||||||
@@ -18,14 +18,13 @@ import { Button, Icon, Toolbar } from '../components'
|
|||||||
import { ImageElement } from './custom-types'
|
import { ImageElement } from './custom-types'
|
||||||
|
|
||||||
const ImagesExample = () => {
|
const ImagesExample = () => {
|
||||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
|
||||||
const editor = useMemo(
|
const editor = useMemo(
|
||||||
() => withImages(withHistory(withReact(createEditor()))),
|
() => withImages(withHistory(withReact(createEditor()))),
|
||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
<InsertImageButton />
|
<InsertImageButton />
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useMemo } from 'react'
|
import React, { useMemo } from 'react'
|
||||||
import isUrl from 'is-url'
|
import isUrl from 'is-url'
|
||||||
import { isKeyHotkey } from 'is-hotkey'
|
import { isKeyHotkey } from 'is-hotkey'
|
||||||
import { css } from '@emotion/css'
|
import { css } from '@emotion/css'
|
||||||
@@ -61,7 +61,6 @@ const initialValue: Descendant[] = [
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
const InlinesExample = () => {
|
const InlinesExample = () => {
|
||||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
|
||||||
const editor = useMemo(
|
const editor = useMemo(
|
||||||
() => withInlines(withHistory(withReact(createEditor()))),
|
() => withInlines(withHistory(withReact(createEditor()))),
|
||||||
[]
|
[]
|
||||||
@@ -92,11 +91,7 @@ const InlinesExample = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SlateReact.Slate
|
<SlateReact.Slate editor={editor} value={initialValue}>
|
||||||
editor={editor}
|
|
||||||
value={value}
|
|
||||||
onChange={value => setValue(value)}
|
|
||||||
>
|
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
<AddLinkButton />
|
<AddLinkButton />
|
||||||
<RemoveLinkButton />
|
<RemoveLinkButton />
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
import Prism from 'prismjs'
|
import Prism from 'prismjs'
|
||||||
import React, { useState, useCallback, useMemo } from 'react'
|
import React, { useCallback, useMemo } from 'react'
|
||||||
import { Slate, Editable, withReact } from 'slate-react'
|
import { Slate, Editable, withReact } from 'slate-react'
|
||||||
import { Text, createEditor, Element, Descendant } from 'slate'
|
import { Text, createEditor, Descendant } from 'slate'
|
||||||
import { withHistory } from 'slate-history'
|
import { withHistory } from 'slate-history'
|
||||||
import { css } from '@emotion/css'
|
import { css } from '@emotion/css'
|
||||||
|
|
||||||
@@ -9,7 +9,6 @@ import { css } from '@emotion/css'
|
|||||||
;Prism.languages.markdown=Prism.languages.extend("markup",{}),Prism.languages.insertBefore("markdown","prolog",{blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},code:[{pattern:/^(?: {4}|\t).+/m,alias:"keyword"},{pattern:/``.+?``|`[^`\n]+`/,alias:"keyword"}],title:[{pattern:/\w+.*(?:\r?\n|\r)(?:==+|--+)/,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#+.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])([\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:/(^|[^\\])(\*\*|__)(?:(?:\r?\n|\r)(?!\r?\n|\r)|.)+?\2/,lookbehind:!0,inside:{punctuation:/^\*\*|^__|\*\*$|__$/}},italic:{pattern:/(^|[^\\])([*_])(?:(?:\r?\n|\r)(?!\r?\n|\r)|.)+?\2/,lookbehind:!0,inside:{punctuation:/^[*_]|[*_]$/}},url:{pattern:/!?\[[^\]]+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)| ?\[[^\]\n]*\])/,inside:{variable:{pattern:/(!?\[)[^\]]+(?=\]$)/,lookbehind:!0},string:{pattern:/"(?:\\.|[^"\\])*"(?=\)$)/}}}}),Prism.languages.markdown.bold.inside.url=Prism.util.clone(Prism.languages.markdown.url),Prism.languages.markdown.italic.inside.url=Prism.util.clone(Prism.languages.markdown.url),Prism.languages.markdown.bold.inside.italic=Prism.util.clone(Prism.languages.markdown.italic),Prism.languages.markdown.italic.inside.bold=Prism.util.clone(Prism.languages.markdown.bold); // prettier-ignore
|
;Prism.languages.markdown=Prism.languages.extend("markup",{}),Prism.languages.insertBefore("markdown","prolog",{blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},code:[{pattern:/^(?: {4}|\t).+/m,alias:"keyword"},{pattern:/``.+?``|`[^`\n]+`/,alias:"keyword"}],title:[{pattern:/\w+.*(?:\r?\n|\r)(?:==+|--+)/,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#+.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])([\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:/(^|[^\\])(\*\*|__)(?:(?:\r?\n|\r)(?!\r?\n|\r)|.)+?\2/,lookbehind:!0,inside:{punctuation:/^\*\*|^__|\*\*$|__$/}},italic:{pattern:/(^|[^\\])([*_])(?:(?:\r?\n|\r)(?!\r?\n|\r)|.)+?\2/,lookbehind:!0,inside:{punctuation:/^[*_]|[*_]$/}},url:{pattern:/!?\[[^\]]+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)| ?\[[^\]\n]*\])/,inside:{variable:{pattern:/(!?\[)[^\]]+(?=\]$)/,lookbehind:!0},string:{pattern:/"(?:\\.|[^"\\])*"(?=\)$)/}}}}),Prism.languages.markdown.bold.inside.url=Prism.util.clone(Prism.languages.markdown.url),Prism.languages.markdown.italic.inside.url=Prism.util.clone(Prism.languages.markdown.url),Prism.languages.markdown.bold.inside.italic=Prism.util.clone(Prism.languages.markdown.italic),Prism.languages.markdown.italic.inside.bold=Prism.util.clone(Prism.languages.markdown.bold); // prettier-ignore
|
||||||
|
|
||||||
const MarkdownPreviewExample = () => {
|
const MarkdownPreviewExample = () => {
|
||||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
|
||||||
const renderLeaf = useCallback(props => <Leaf {...props} />, [])
|
const renderLeaf = useCallback(props => <Leaf {...props} />, [])
|
||||||
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
||||||
const decorate = useCallback(([node, path]) => {
|
const decorate = useCallback(([node, path]) => {
|
||||||
@@ -51,7 +50,7 @@ const MarkdownPreviewExample = () => {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<Editable
|
<Editable
|
||||||
decorate={decorate}
|
decorate={decorate}
|
||||||
renderLeaf={renderLeaf}
|
renderLeaf={renderLeaf}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useCallback, useMemo } from 'react'
|
import React, { useCallback, useMemo } from 'react'
|
||||||
import { Slate, Editable, withReact } from 'slate-react'
|
import { Slate, Editable, withReact } from 'slate-react'
|
||||||
import {
|
import {
|
||||||
Editor,
|
Editor,
|
||||||
@@ -26,14 +26,13 @@ const SHORTCUTS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const MarkdownShortcutsExample = () => {
|
const MarkdownShortcutsExample = () => {
|
||||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
|
||||||
const renderElement = useCallback(props => <Element {...props} />, [])
|
const renderElement = useCallback(props => <Element {...props} />, [])
|
||||||
const editor = useMemo(
|
const editor = useMemo(
|
||||||
() => withShortcuts(withReact(withHistory(createEditor()))),
|
() => withShortcuts(withReact(withHistory(createEditor()))),
|
||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<Editable
|
<Editable
|
||||||
renderElement={renderElement}
|
renderElement={renderElement}
|
||||||
placeholder="Write some markdown..."
|
placeholder="Write some markdown..."
|
||||||
|
@@ -15,7 +15,6 @@ import { MentionElement } from './custom-types'
|
|||||||
|
|
||||||
const MentionExample = () => {
|
const MentionExample = () => {
|
||||||
const ref = useRef<HTMLDivElement | null>()
|
const ref = useRef<HTMLDivElement | null>()
|
||||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
|
||||||
const [target, setTarget] = useState<Range | undefined>()
|
const [target, setTarget] = useState<Range | undefined>()
|
||||||
const [index, setIndex] = useState(0)
|
const [index, setIndex] = useState(0)
|
||||||
const [search, setSearch] = useState('')
|
const [search, setSearch] = useState('')
|
||||||
@@ -73,9 +72,8 @@ const MentionExample = () => {
|
|||||||
return (
|
return (
|
||||||
<Slate
|
<Slate
|
||||||
editor={editor}
|
editor={editor}
|
||||||
value={value}
|
value={initialValue}
|
||||||
onChange={value => {
|
onChange={() => {
|
||||||
setValue(value)
|
|
||||||
const { selection } = editor
|
const { selection } = editor
|
||||||
|
|
||||||
if (selection && Range.isCollapsed(selection)) {
|
if (selection && Range.isCollapsed(selection)) {
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useCallback, useMemo } from 'react'
|
import React, { useCallback, useMemo } from 'react'
|
||||||
import { jsx } from 'slate-hyperscript'
|
import { jsx } from 'slate-hyperscript'
|
||||||
import { Transforms, createEditor, Descendant } from 'slate'
|
import { Transforms, createEditor, Descendant } from 'slate'
|
||||||
import { withHistory } from 'slate-history'
|
import { withHistory } from 'slate-history'
|
||||||
@@ -84,7 +84,6 @@ export const deserialize = el => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const PasteHtmlExample = () => {
|
const PasteHtmlExample = () => {
|
||||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
|
||||||
const renderElement = useCallback(props => <Element {...props} />, [])
|
const renderElement = useCallback(props => <Element {...props} />, [])
|
||||||
const renderLeaf = useCallback(props => <Leaf {...props} />, [])
|
const renderLeaf = useCallback(props => <Leaf {...props} />, [])
|
||||||
const editor = useMemo(
|
const editor = useMemo(
|
||||||
@@ -92,7 +91,7 @@ const PasteHtmlExample = () => {
|
|||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<Editable
|
<Editable
|
||||||
renderElement={renderElement}
|
renderElement={renderElement}
|
||||||
renderLeaf={renderLeaf}
|
renderLeaf={renderLeaf}
|
||||||
|
@@ -1,13 +1,12 @@
|
|||||||
import React, { useState, useMemo } from 'react'
|
import React, { useMemo } from 'react'
|
||||||
import { createEditor, Descendant } from 'slate'
|
import { createEditor, Descendant } from 'slate'
|
||||||
import { Slate, Editable, withReact } from 'slate-react'
|
import { Slate, Editable, withReact } from 'slate-react'
|
||||||
import { withHistory } from 'slate-history'
|
import { withHistory } from 'slate-history'
|
||||||
|
|
||||||
const PlainTextExample = () => {
|
const PlainTextExample = () => {
|
||||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
|
||||||
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<Editable placeholder="Enter some plain text..." />
|
<Editable placeholder="Enter some plain text..." />
|
||||||
</Slate>
|
</Slate>
|
||||||
)
|
)
|
||||||
|
@@ -1,12 +1,11 @@
|
|||||||
import React, { useState, useMemo } from 'react'
|
import React, { useMemo } from 'react'
|
||||||
import { createEditor, Descendant, Element } from 'slate'
|
import { createEditor, Descendant } from 'slate'
|
||||||
import { Slate, Editable, withReact } from 'slate-react'
|
import { Slate, Editable, withReact } from 'slate-react'
|
||||||
|
|
||||||
const ReadOnlyExample = () => {
|
const ReadOnlyExample = () => {
|
||||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
|
||||||
const editor = useMemo(() => withReact(createEditor()), [])
|
const editor = useMemo(() => withReact(createEditor()), [])
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<Editable readOnly placeholder="Enter some plain text..." />
|
<Editable readOnly placeholder="Enter some plain text..." />
|
||||||
</Slate>
|
</Slate>
|
||||||
)
|
)
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback, useMemo, useState } from 'react'
|
import React, { useCallback, useMemo } from 'react'
|
||||||
import isHotkey from 'is-hotkey'
|
import isHotkey from 'is-hotkey'
|
||||||
import { Editable, withReact, useSlate, Slate } from 'slate-react'
|
import { Editable, withReact, useSlate, Slate } from 'slate-react'
|
||||||
import {
|
import {
|
||||||
@@ -23,13 +23,12 @@ const LIST_TYPES = ['numbered-list', 'bulleted-list']
|
|||||||
const TEXT_ALIGN_TYPES = ['left', 'center', 'right', 'justify']
|
const TEXT_ALIGN_TYPES = ['left', 'center', 'right', 'justify']
|
||||||
|
|
||||||
const RichTextExample = () => {
|
const RichTextExample = () => {
|
||||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
|
||||||
const renderElement = useCallback(props => <Element {...props} />, [])
|
const renderElement = useCallback(props => <Element {...props} />, [])
|
||||||
const renderLeaf = useCallback(props => <Leaf {...props} />, [])
|
const renderLeaf = useCallback(props => <Leaf {...props} />, [])
|
||||||
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
<MarkButton format="bold" icon="format_bold" />
|
<MarkButton format="bold" icon="format_bold" />
|
||||||
<MarkButton format="italic" icon="format_italic" />
|
<MarkButton format="italic" icon="format_italic" />
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useMemo } from 'react'
|
import React, { useMemo } from 'react'
|
||||||
import { createEditor, Descendant } from 'slate'
|
import { createEditor, Descendant } from 'slate'
|
||||||
import { Slate, Editable, withReact } from 'slate-react'
|
import { Slate, Editable, withReact } from 'slate-react'
|
||||||
import { withHistory } from 'slate-history'
|
import { withHistory } from 'slate-history'
|
||||||
@@ -49,10 +49,9 @@ const ScrollIntoViewExample = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const PlainTextEditor = () => {
|
const PlainTextEditor = () => {
|
||||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
|
||||||
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<Editable placeholder="Enter some plain text..." />
|
<Editable placeholder="Enter some plain text..." />
|
||||||
</Slate>
|
</Slate>
|
||||||
)
|
)
|
||||||
|
@@ -7,7 +7,6 @@ import { withHistory } from 'slate-history'
|
|||||||
import { Icon, Toolbar } from '../components'
|
import { Icon, Toolbar } from '../components'
|
||||||
|
|
||||||
const SearchHighlightingExample = () => {
|
const SearchHighlightingExample = () => {
|
||||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
|
||||||
const [search, setSearch] = useState<string | undefined>()
|
const [search, setSearch] = useState<string | undefined>()
|
||||||
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
||||||
const decorate = useCallback(
|
const decorate = useCallback(
|
||||||
@@ -38,7 +37,7 @@ const SearchHighlightingExample = () => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
<div
|
<div
|
||||||
className={css`
|
className={css`
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
import React, { useState, useMemo, useRef, useEffect } from 'react'
|
import React, { useMemo, useRef, useEffect } from 'react'
|
||||||
import { createEditor, Descendant } from 'slate'
|
import { createEditor, Descendant } from 'slate'
|
||||||
import { Slate, Editable, withReact } from 'slate-react'
|
import { Slate, Editable, withReact } from 'slate-react'
|
||||||
import { withHistory } from 'slate-history'
|
import { withHistory } from 'slate-history'
|
||||||
@@ -28,11 +28,10 @@ const ShadowDOM = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ShadowEditor = () => {
|
const ShadowEditor = () => {
|
||||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
|
||||||
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<Editable placeholder="Enter some plain text..." />
|
<Editable placeholder="Enter some plain text..." />
|
||||||
</Slate>
|
</Slate>
|
||||||
)
|
)
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useCallback, useMemo } from 'react'
|
import React, { useCallback, useMemo } from 'react'
|
||||||
import { Slate, Editable, withReact } from 'slate-react'
|
import { Slate, Editable, withReact } from 'slate-react'
|
||||||
import {
|
import {
|
||||||
Editor,
|
Editor,
|
||||||
@@ -11,7 +11,6 @@ import {
|
|||||||
import { withHistory } from 'slate-history'
|
import { withHistory } from 'slate-history'
|
||||||
|
|
||||||
const TablesExample = () => {
|
const TablesExample = () => {
|
||||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
|
||||||
const renderElement = useCallback(props => <Element {...props} />, [])
|
const renderElement = useCallback(props => <Element {...props} />, [])
|
||||||
const renderLeaf = useCallback(props => <Leaf {...props} />, [])
|
const renderLeaf = useCallback(props => <Leaf {...props} />, [])
|
||||||
const editor = useMemo(
|
const editor = useMemo(
|
||||||
@@ -19,7 +18,7 @@ const TablesExample = () => {
|
|||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
<Slate editor={editor} value={initialValue}>
|
||||||
<Editable renderElement={renderElement} renderLeaf={renderLeaf} />
|
<Editable renderElement={renderElement} renderLeaf={renderLeaf} />
|
||||||
</Slate>
|
</Slate>
|
||||||
)
|
)
|
||||||
|
Reference in New Issue
Block a user