'Add paragraph after image within a slate-react text editor
I am currently working on rich text editor based on slatejs. I need to implement possibility to insert paragraph right after an image, when image is focused. Now when image has focus and I press Enter
button - nothing happend. It should insert new empty paragraph right after the image.
Same behavior in example https://www.slatejs.org/examples/images
Any help appreciated
Solution 1:[1]
If you are selecting a void node (Image node), pressing enter
won't add a new line by default. The most upvoted answer adds a new line only on image insert, which doesn't address the question.
Here's a plugin on how to give the editor your desired behavior.
import { Editor, Node, Path, Range, Transforms } from 'slate'
export const withCorrectVoidBehavior = editor => {
const { deleteBackward, insertBreak } = editor
// if current selection is void node, insert a default node below
editor.insertBreak = () => {
if (!editor.selection || !Range.isCollapsed(editor.selection)) {
return insertBreak()
}
const selectedNodePath = Path.parent(editor.selection.anchor.path)
const selectedNode = Node.get(editor, selectedNodePath)
if (Editor.isVoid(editor, selectedNode)) {
Editor.insertNode(editor, {
type: 'paragraph',
children: [{ text: '' }],
})
return
}
insertBreak()
}
// if prev node is a void node, remove the current node and select the void node
editor.deleteBackward = unit => {
if (
!editor.selection ||
!Range.isCollapsed(editor.selection) ||
editor.selection.anchor.offset !== 0
) {
return deleteBackward(unit)
}
const parentPath = Path.parent(editor.selection.anchor.path)
const parentNode = Node.get(editor, parentPath)
const parentIsEmpty = Node.string(parentNode).length === 0
if (parentIsEmpty && Path.hasPrevious(parentPath)) {
const prevNodePath = Path.previous(parentPath)
const prevNode = Node.get(editor, prevNodePath)
if (Editor.isVoid(editor, prevNode)) {
return Transforms.removeNodes(editor)
}
}
deleteBackward(unit)
}
return editor
}
We override the insertBreak
behavior (which gets called on carrige return) and insert a blank line instead by calling Editor.insertNode(editor, blankNode)
if the selected node is void.
We also override the deleteBackward
behavior. Without the plugin, deleting an empty line right after a void node will delete the node too! Now, instead of deleting the node before, we delete the blank line and select the node before.
To use this plugin, you would do something like:
const editor = useMemo(() => withCorrectVoidBehavior(withReact(createEditor())), []);
I stole the plugin code from: https://github.com/ianstormtaylor/slate/issues/3991
Solution 2:[2]
Editing the source that SlateJS gave, I just added a paragraph node within the insertImage()
function.
SlateJS Source:
const insertImage = (editor, url) => {
const text = { text: '' }
const image = { type: 'image', url, children: [text] }
Transforms.insertNodes(editor, image)
}
Edit To:
const insertImage = (editor, url) => {
const text = { text: '' }
const image = [
{
type: 'image',
url,
children: [text]
},
{
type: 'paragraph',
children: [text],
}
];
Transforms.insertNodes(editor, image);
};
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Tarkan |
Solution 2 | Asolace |