mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-13 18:53:59 +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.
|
||||
|
||||
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 initialValue = []
|
||||
|
||||
const App = () => {
|
||||
const [editor] = useState(() => withReact(createEditor()))
|
||||
const [value, setValue] = useState([])
|
||||
// Render the Slate context.
|
||||
return (
|
||||
<Slate
|
||||
editor={editor}
|
||||
value={value}
|
||||
onChange={newValue => setValue(newValue)}
|
||||
/>
|
||||
)
|
||||
return <Slate editor={editor} value={initialValue} />
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
@@ -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:
|
||||
|
||||
```jsx
|
||||
const initialValue = []
|
||||
|
||||
const App = () => {
|
||||
const [editor] = useState(() => withReact(createEditor()))
|
||||
const [value, setValue] = useState([])
|
||||
return (
|
||||
// Add the editable component inside the context.
|
||||
<Slate
|
||||
editor={editor}
|
||||
value={value}
|
||||
onChange={newValue => setValue(newValue)}
|
||||
>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Editable />
|
||||
</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:
|
||||
|
||||
```jsx
|
||||
const App = () => {
|
||||
const [editor] = useState(() => withReact(createEditor()))
|
||||
// Add the initial value when setting up our state.
|
||||
const [value, setValue] = useState([
|
||||
// Add the initial value.
|
||||
const initialValue = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: 'A line of text in a paragraph.' }],
|
||||
},
|
||||
])
|
||||
]
|
||||
|
||||
const App = () => {
|
||||
const [editor] = useState(() => withReact(createEditor())
|
||||
const [value, setValue] = useState()
|
||||
|
||||
return (
|
||||
<Slate
|
||||
editor={editor}
|
||||
value={value}
|
||||
onChange={newValue => setValue(newValue)}
|
||||
>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Editable />
|
||||
</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:
|
||||
|
||||
```jsx
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
const [value, setValue] = useState([
|
||||
const initialValue = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: 'A line of text in a paragraph.' }],
|
||||
},
|
||||
])
|
||||
]
|
||||
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Editable />
|
||||
</Slate>
|
||||
)
|
||||
@@ -29,17 +30,18 @@ const App = () => {
|
||||
Now we add an `onKeyDown` handler:
|
||||
|
||||
```jsx
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
const [value, setValue] = useState([
|
||||
const initialValue = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: 'A line of text in a paragraph.' }],
|
||||
},
|
||||
])
|
||||
]
|
||||
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Editable
|
||||
// Define a new handler which prints the key that was pressed.
|
||||
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:
|
||||
|
||||
```jsx
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
const [value, setValue] = useState([
|
||||
const initialValue = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: 'A line of text in a paragraph.' }],
|
||||
},
|
||||
])
|
||||
]
|
||||
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Editable
|
||||
onKeyDown={event => {
|
||||
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:
|
||||
|
||||
```jsx
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
const [value, setValue] = useState([
|
||||
const initialValue = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: 'A line of text in a paragraph.' }],
|
||||
},
|
||||
])
|
||||
]
|
||||
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Editable
|
||||
onKeyDown={event => {
|
||||
if (event.key === '&') {
|
||||
@@ -65,14 +66,15 @@ const DefaultElement = props => {
|
||||
Now, let's add that renderer to our `Editor`:
|
||||
|
||||
```jsx
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
const [value, setValue] = useState([
|
||||
const initialValue = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: 'A line of text in a paragraph.' }],
|
||||
},
|
||||
])
|
||||
]
|
||||
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
|
||||
// Define a rendering function based on the element passed to `props`. We use
|
||||
// `useCallback` here to memoize the function for subsequent renders.
|
||||
@@ -86,7 +88,7 @@ const App = () => {
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Editable
|
||||
// Pass in the `renderElement` function.
|
||||
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 { Editor, Transforms } from 'slate'
|
||||
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
const [value, setValue] = useState([
|
||||
const initialValue = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: 'A line of text in a paragraph.' }],
|
||||
},
|
||||
])
|
||||
]
|
||||
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
|
||||
const renderElement = useCallback(props => {
|
||||
switch (props.element.type) {
|
||||
@@ -139,7 +142,7 @@ const App = () => {
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Editable
|
||||
renderElement={renderElement}
|
||||
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:
|
||||
|
||||
```jsx
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
const [value, setValue] = useState([
|
||||
const initialValue = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: 'A line of text in a paragraph.' }],
|
||||
},
|
||||
])
|
||||
]
|
||||
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
|
||||
const renderElement = useCallback(props => {
|
||||
switch (props.element.type) {
|
||||
@@ -196,7 +200,7 @@ const App = () => {
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Editable
|
||||
renderElement={renderElement}
|
||||
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:
|
||||
|
||||
```jsx
|
||||
const renderElement = (props) => {
|
||||
const renderElement = props => {
|
||||
switch (props.element.type) {
|
||||
case 'code':
|
||||
return <CodeElement {...props} />
|
||||
default:
|
||||
return <DefaultElement {...props} />
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
const [value, setValue] = useState([
|
||||
const initialValue = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: 'A line of text in a paragraph.' }],
|
||||
},
|
||||
])
|
||||
]
|
||||
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Editable
|
||||
renderElement={renderElement}
|
||||
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:
|
||||
|
||||
```jsx
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
const [value, setValue] = useState([
|
||||
const initialValue = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: 'A line of text in a paragraph.' }],
|
||||
},
|
||||
])
|
||||
]
|
||||
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
|
||||
const renderElement = useCallback(props => {
|
||||
switch (props.element.type) {
|
||||
@@ -71,7 +73,7 @@ const App = () => {
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={value}>
|
||||
<Editable
|
||||
renderElement={renderElement}
|
||||
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.
|
||||
|
||||
```jsx
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
const [value, setValue] = useState([
|
||||
const initialValue = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: 'A line of text in a paragraph.' }],
|
||||
},
|
||||
])
|
||||
]
|
||||
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
|
||||
const renderElement = useCallback(props => {
|
||||
switch (props.element.type) {
|
||||
@@ -161,7 +164,7 @@ const App = () => {
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Editable
|
||||
renderElement={renderElement}
|
||||
// Pass in the `renderLeaf` function.
|
||||
|
@@ -11,14 +11,15 @@ Let's see how this works.
|
||||
We'll start with our app from earlier:
|
||||
|
||||
```jsx
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
const [value, setValue] = useState([
|
||||
const initialValue = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: 'A line of text in a paragraph.' }],
|
||||
},
|
||||
])
|
||||
]
|
||||
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
|
||||
const renderElement = useCallback(props => {
|
||||
switch (props.element.type) {
|
||||
@@ -34,7 +35,7 @@ const App = () => {
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Editable
|
||||
renderElement={renderElement}
|
||||
renderLeaf={renderLeaf}
|
||||
@@ -117,14 +118,15 @@ const CustomEditor = {
|
||||
},
|
||||
}
|
||||
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
const [value, setValue] = useState([
|
||||
const initialValue = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: 'A line of text in a paragraph.' }],
|
||||
},
|
||||
])
|
||||
]
|
||||
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
|
||||
const renderElement = useCallback(props => {
|
||||
switch (props.element.type) {
|
||||
@@ -140,7 +142,7 @@ const App = () => {
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Editable
|
||||
renderElement={renderElement}
|
||||
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:
|
||||
|
||||
```jsx
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
const [value, setValue] = useState([
|
||||
const initialValue = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: 'A line of text in a paragraph.' }],
|
||||
},
|
||||
])
|
||||
]
|
||||
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
|
||||
const renderElement = useCallback(props => {
|
||||
switch (props.element.type) {
|
||||
@@ -197,7 +200,7 @@ const App = () => {
|
||||
|
||||
return (
|
||||
// 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>
|
||||
<button
|
||||
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:
|
||||
|
||||
```jsx
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
const [value, setValue] = useState([
|
||||
const initialValue = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: 'A line of text in a paragraph.' }],
|
||||
},
|
||||
])
|
||||
]
|
||||
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Editable />
|
||||
</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:
|
||||
|
||||
```jsx
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
const [value, setValue] = useState([
|
||||
const initialValue = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: 'A line of text in a paragraph.' }],
|
||||
},
|
||||
])
|
||||
]
|
||||
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
|
||||
return (
|
||||
<Slate
|
||||
editor={editor}
|
||||
value={value}
|
||||
value={initialValue}
|
||||
onChange={value => {
|
||||
setValue(value)
|
||||
|
||||
const isAstChange = editor.operations.some(
|
||||
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 editor = useMemo(() => withReact(createEditor()), [])
|
||||
// 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')) || [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: 'A line of text in a paragraph.' }],
|
||||
},
|
||||
]
|
||||
],
|
||||
[]
|
||||
)
|
||||
|
||||
return (
|
||||
<Slate
|
||||
editor={editor}
|
||||
value={value}
|
||||
value={initialValue}
|
||||
onChange={value => {
|
||||
setValue(value)
|
||||
const isAstChange = editor.operations.some(
|
||||
op => 'set_selection' !== op.type
|
||||
)
|
||||
@@ -136,16 +136,16 @@ const deserialize = string => {
|
||||
const App = () => {
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
// Use our deserializing function to read the data from Local Storage.
|
||||
const [value, setValue] = useState(
|
||||
deserialize(localStorage.getItem('content')) || ''
|
||||
const initialValue = useMemo(
|
||||
deserialize(localStorage.getItem('content')) || '',
|
||||
[]
|
||||
)
|
||||
|
||||
return (
|
||||
<Slate
|
||||
editor={editor}
|
||||
value={value}
|
||||
value={initialValue}
|
||||
onChange={value => {
|
||||
setValue(value)
|
||||
const isAstChange = editor.operations.some(
|
||||
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.
|
||||
|
||||
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
|
||||
/**
|
||||
|
@@ -20,7 +20,7 @@ export const Slate = (props: {
|
||||
editor: ReactEditor
|
||||
value: Descendant[]
|
||||
children: React.ReactNode
|
||||
onChange: (value: Descendant[]) => void
|
||||
onChange?: (value: Descendant[]) => void
|
||||
}) => {
|
||||
const { editor, children, onChange, value, ...rest } = props
|
||||
const unmountRef = useRef(false)
|
||||
@@ -48,7 +48,10 @@ export const Slate = (props: {
|
||||
} = getSelectorContext(editor)
|
||||
|
||||
const onContextChange = useCallback(() => {
|
||||
if (onChange) {
|
||||
onChange(editor.children)
|
||||
}
|
||||
|
||||
setContext([editor])
|
||||
handleSelectorChange(editor)
|
||||
}, [onChange])
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useMemo, useCallback } from 'react'
|
||||
import React, { useMemo, useCallback } from 'react'
|
||||
import {
|
||||
Slate,
|
||||
Editable,
|
||||
@@ -66,7 +66,6 @@ const initialValue: Descendant[] = [
|
||||
]
|
||||
|
||||
const CheckListsExample = () => {
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const renderElement = useCallback(props => <Element {...props} />, [])
|
||||
const editor = useMemo(
|
||||
() => withChecklists(withHistory(withReact(createEditor()))),
|
||||
@@ -74,7 +73,7 @@ const CheckListsExample = () => {
|
||||
)
|
||||
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Editable
|
||||
renderElement={renderElement}
|
||||
placeholder="Get to work…"
|
||||
|
@@ -10,7 +10,6 @@ import { withHistory } from 'slate-history'
|
||||
import { css } from '@emotion/css'
|
||||
|
||||
const CodeHighlightingExample = () => {
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const [language, setLanguage] = useState('html')
|
||||
const renderLeaf = useCallback(props => <Leaf {...props} />, [])
|
||||
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
||||
@@ -46,7 +45,7 @@ const CodeHighlightingExample = () => {
|
||||
)
|
||||
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<div
|
||||
contentEditable={false}
|
||||
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 { Slate, Editable, withReact } from 'slate-react'
|
||||
import { withHistory } from 'slate-history'
|
||||
|
||||
const initialValue: Descendant[] = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
]
|
||||
|
||||
const PlainTextExample = () => {
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Editable
|
||||
placeholder="Type something"
|
||||
renderPlaceholder={({ children, attributes }) => (
|
||||
@@ -24,11 +30,4 @@ const PlainTextExample = () => {
|
||||
)
|
||||
}
|
||||
|
||||
const initialValue: Descendant[] = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
]
|
||||
|
||||
export default PlainTextExample
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useMemo } from 'react'
|
||||
import React, { useMemo } from 'react'
|
||||
import {
|
||||
Transforms,
|
||||
createEditor,
|
||||
@@ -14,10 +14,9 @@ import {
|
||||
} from 'slate-react'
|
||||
|
||||
const EmbedsExample = () => {
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const editor = useMemo(() => withEmbeds(withReact(createEditor())), [])
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Editable
|
||||
renderElement={props => <Element {...props} />}
|
||||
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 {
|
||||
Transforms,
|
||||
@@ -64,14 +64,13 @@ const withLayout = editor => {
|
||||
}
|
||||
|
||||
const ForcedLayoutExample = () => {
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const renderElement = useCallback(props => <Element {...props} />, [])
|
||||
const editor = useMemo(
|
||||
() => withLayout(withHistory(withReact(createEditor()))),
|
||||
[]
|
||||
)
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Editable
|
||||
renderElement={renderElement}
|
||||
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 {
|
||||
Editor,
|
||||
@@ -14,11 +14,10 @@ import { withHistory } from 'slate-history'
|
||||
import { Button, Icon, Menu, Portal } from '../components'
|
||||
|
||||
const HoveringMenuExample = () => {
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
||||
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<HoveringToolbar />
|
||||
<Editable
|
||||
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 { createEditor, Descendant } from 'slate'
|
||||
import { Slate, Editable, withReact } from 'slate-react'
|
||||
@@ -22,11 +22,10 @@ for (let h = 0; h < HEADINGS; h++) {
|
||||
}
|
||||
|
||||
const HugeDocumentExample = () => {
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const renderElement = useCallback(props => <Element {...props} />, [])
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Editable renderElement={renderElement} spellCheck autoFocus />
|
||||
</Slate>
|
||||
)
|
||||
|
@@ -15,7 +15,6 @@ const HOTKEYS = {
|
||||
}
|
||||
|
||||
const IFrameExample = () => {
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const renderElement = useCallback(
|
||||
({ attributes, children }) => <p {...attributes}>{children}</p>,
|
||||
[]
|
||||
@@ -26,7 +25,7 @@ const IFrameExample = () => {
|
||||
const handleBlur = useCallback(() => ReactEditor.deselect(editor), [editor])
|
||||
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Toolbar>
|
||||
<MarkButton format="bold" icon="format_bold" />
|
||||
<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 isUrl from 'is-url'
|
||||
import { Transforms, createEditor, Descendant } from 'slate'
|
||||
@@ -18,14 +18,13 @@ import { Button, Icon, Toolbar } from '../components'
|
||||
import { ImageElement } from './custom-types'
|
||||
|
||||
const ImagesExample = () => {
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const editor = useMemo(
|
||||
() => withImages(withHistory(withReact(createEditor()))),
|
||||
[]
|
||||
)
|
||||
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Toolbar>
|
||||
<InsertImageButton />
|
||||
</Toolbar>
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useMemo } from 'react'
|
||||
import React, { useMemo } from 'react'
|
||||
import isUrl from 'is-url'
|
||||
import { isKeyHotkey } from 'is-hotkey'
|
||||
import { css } from '@emotion/css'
|
||||
@@ -61,7 +61,6 @@ const initialValue: Descendant[] = [
|
||||
},
|
||||
]
|
||||
const InlinesExample = () => {
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const editor = useMemo(
|
||||
() => withInlines(withHistory(withReact(createEditor()))),
|
||||
[]
|
||||
@@ -92,11 +91,7 @@ const InlinesExample = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<SlateReact.Slate
|
||||
editor={editor}
|
||||
value={value}
|
||||
onChange={value => setValue(value)}
|
||||
>
|
||||
<SlateReact.Slate editor={editor} value={initialValue}>
|
||||
<Toolbar>
|
||||
<AddLinkButton />
|
||||
<RemoveLinkButton />
|
||||
|
@@ -1,7 +1,7 @@
|
||||
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 { Text, createEditor, Element, Descendant } from 'slate'
|
||||
import { Text, createEditor, Descendant } from 'slate'
|
||||
import { withHistory } from 'slate-history'
|
||||
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
|
||||
|
||||
const MarkdownPreviewExample = () => {
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const renderLeaf = useCallback(props => <Leaf {...props} />, [])
|
||||
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
||||
const decorate = useCallback(([node, path]) => {
|
||||
@@ -51,7 +50,7 @@ const MarkdownPreviewExample = () => {
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Editable
|
||||
decorate={decorate}
|
||||
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 {
|
||||
Editor,
|
||||
@@ -26,14 +26,13 @@ const SHORTCUTS = {
|
||||
}
|
||||
|
||||
const MarkdownShortcutsExample = () => {
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const renderElement = useCallback(props => <Element {...props} />, [])
|
||||
const editor = useMemo(
|
||||
() => withShortcuts(withReact(withHistory(createEditor()))),
|
||||
[]
|
||||
)
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Editable
|
||||
renderElement={renderElement}
|
||||
placeholder="Write some markdown..."
|
||||
|
@@ -15,7 +15,6 @@ import { MentionElement } from './custom-types'
|
||||
|
||||
const MentionExample = () => {
|
||||
const ref = useRef<HTMLDivElement | null>()
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const [target, setTarget] = useState<Range | undefined>()
|
||||
const [index, setIndex] = useState(0)
|
||||
const [search, setSearch] = useState('')
|
||||
@@ -73,9 +72,8 @@ const MentionExample = () => {
|
||||
return (
|
||||
<Slate
|
||||
editor={editor}
|
||||
value={value}
|
||||
onChange={value => {
|
||||
setValue(value)
|
||||
value={initialValue}
|
||||
onChange={() => {
|
||||
const { selection } = editor
|
||||
|
||||
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 { Transforms, createEditor, Descendant } from 'slate'
|
||||
import { withHistory } from 'slate-history'
|
||||
@@ -84,7 +84,6 @@ export const deserialize = el => {
|
||||
}
|
||||
|
||||
const PasteHtmlExample = () => {
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const renderElement = useCallback(props => <Element {...props} />, [])
|
||||
const renderLeaf = useCallback(props => <Leaf {...props} />, [])
|
||||
const editor = useMemo(
|
||||
@@ -92,7 +91,7 @@ const PasteHtmlExample = () => {
|
||||
[]
|
||||
)
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Editable
|
||||
renderElement={renderElement}
|
||||
renderLeaf={renderLeaf}
|
||||
|
@@ -1,13 +1,12 @@
|
||||
import React, { useState, useMemo } from 'react'
|
||||
import React, { useMemo } from 'react'
|
||||
import { createEditor, Descendant } from 'slate'
|
||||
import { Slate, Editable, withReact } from 'slate-react'
|
||||
import { withHistory } from 'slate-history'
|
||||
|
||||
const PlainTextExample = () => {
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Editable placeholder="Enter some plain text..." />
|
||||
</Slate>
|
||||
)
|
||||
|
@@ -1,12 +1,11 @@
|
||||
import React, { useState, useMemo } from 'react'
|
||||
import { createEditor, Descendant, Element } from 'slate'
|
||||
import React, { useMemo } from 'react'
|
||||
import { createEditor, Descendant } from 'slate'
|
||||
import { Slate, Editable, withReact } from 'slate-react'
|
||||
|
||||
const ReadOnlyExample = () => {
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Editable readOnly placeholder="Enter some plain text..." />
|
||||
</Slate>
|
||||
)
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import React, { useCallback, useMemo, useState } from 'react'
|
||||
import React, { useCallback, useMemo } from 'react'
|
||||
import isHotkey from 'is-hotkey'
|
||||
import { Editable, withReact, useSlate, Slate } from 'slate-react'
|
||||
import {
|
||||
@@ -23,13 +23,12 @@ const LIST_TYPES = ['numbered-list', 'bulleted-list']
|
||||
const TEXT_ALIGN_TYPES = ['left', 'center', 'right', 'justify']
|
||||
|
||||
const RichTextExample = () => {
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const renderElement = useCallback(props => <Element {...props} />, [])
|
||||
const renderLeaf = useCallback(props => <Leaf {...props} />, [])
|
||||
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
||||
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Toolbar>
|
||||
<MarkButton format="bold" icon="format_bold" />
|
||||
<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 { Slate, Editable, withReact } from 'slate-react'
|
||||
import { withHistory } from 'slate-history'
|
||||
@@ -49,10 +49,9 @@ const ScrollIntoViewExample = () => {
|
||||
}
|
||||
|
||||
const PlainTextEditor = () => {
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Editable placeholder="Enter some plain text..." />
|
||||
</Slate>
|
||||
)
|
||||
|
@@ -7,7 +7,6 @@ import { withHistory } from 'slate-history'
|
||||
import { Icon, Toolbar } from '../components'
|
||||
|
||||
const SearchHighlightingExample = () => {
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const [search, setSearch] = useState<string | undefined>()
|
||||
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
||||
const decorate = useCallback(
|
||||
@@ -38,7 +37,7 @@ const SearchHighlightingExample = () => {
|
||||
)
|
||||
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Toolbar>
|
||||
<div
|
||||
className={css`
|
||||
|
@@ -1,5 +1,5 @@
|
||||
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 { Slate, Editable, withReact } from 'slate-react'
|
||||
import { withHistory } from 'slate-history'
|
||||
@@ -28,11 +28,10 @@ const ShadowDOM = () => {
|
||||
}
|
||||
|
||||
const ShadowEditor = () => {
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
||||
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Editable placeholder="Enter some plain text..." />
|
||||
</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 {
|
||||
Editor,
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
import { withHistory } from 'slate-history'
|
||||
|
||||
const TablesExample = () => {
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const renderElement = useCallback(props => <Element {...props} />, [])
|
||||
const renderLeaf = useCallback(props => <Leaf {...props} />, [])
|
||||
const editor = useMemo(
|
||||
@@ -19,7 +18,7 @@ const TablesExample = () => {
|
||||
[]
|
||||
)
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
<Slate editor={editor} value={initialValue}>
|
||||
<Editable renderElement={renderElement} renderLeaf={renderLeaf} />
|
||||
</Slate>
|
||||
)
|
||||
|
Reference in New Issue
Block a user