1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-13 18:53:59 +02:00

Fix crash when a void node deletes itself on click (#4616)

* Fix crash when a void node deletes itself on click

Fixes https://github.com/ianstormtaylor/slate/issues/4240

* Add 'image delete' feature to example

My immediate motivation is to demonstrate the bug that this fixes. But
this is also a very common editor feature, and I think it's valuable
to show how to achieve it.

* add changeset

* fix:eslint

* revert changes to mentions.tsx
This commit is contained in:
Jim Fisher
2021-10-24 15:31:00 +01:00
committed by GitHub
parent b50a772136
commit 77d9f60ab5
3 changed files with 63 additions and 12 deletions

View File

@@ -0,0 +1,5 @@
---
'slate-react': patch
---
Fixed crash on self-deleting void node

View File

@@ -706,19 +706,29 @@ export const Editable = (props: EditableProps) => {
) {
const node = ReactEditor.toSlateNode(editor, event.target)
const path = ReactEditor.findPath(editor, node)
const start = Editor.start(editor, path)
const end = Editor.end(editor, path)
const startVoid = Editor.void(editor, { at: start })
const endVoid = Editor.void(editor, { at: end })
// At this time, the Slate document may be arbitrarily different,
// because onClick handlers can change the document before we get here.
// Therefore we must check that this path actually exists,
// and that it still refers to the same node.
if (Editor.hasPath(editor, path)) {
const lookupNode = Node.get(editor, path)
if (lookupNode === node) {
const start = Editor.start(editor, path)
const end = Editor.end(editor, path)
if (
startVoid &&
endVoid &&
Path.equals(startVoid[1], endVoid[1])
) {
const range = Editor.range(editor, start)
Transforms.select(editor, range)
const startVoid = Editor.void(editor, { at: start })
const endVoid = Editor.void(editor, { at: end })
if (
startVoid &&
endVoid &&
Path.equals(startVoid[1], endVoid[1])
) {
const range = Editor.range(editor, start)
Transforms.select(editor, range)
}
}
}
}
},

View File

@@ -9,6 +9,7 @@ import {
useSelected,
useFocused,
withReact,
ReactEditor,
} from 'slate-react'
import { withHistory } from 'slate-history'
import { css } from 'emotion'
@@ -89,12 +90,20 @@ const Element = props => {
}
const Image = ({ attributes, children, element }) => {
const editor = useSlateStatic()
const path = ReactEditor.findPath(editor, element)
const selected = useSelected()
const focused = useFocused()
return (
<div {...attributes}>
{children}
<div contentEditable={false}>
<div
contentEditable={false}
className={css`
position: relative;
`}
>
<img
src={element.url}
className={css`
@@ -104,6 +113,19 @@ const Image = ({ attributes, children, element }) => {
box-shadow: ${selected && focused ? '0 0 0 3px #B4D5FF' : 'none'};
`}
/>
<Button
active
onClick={() => Transforms.removeNodes(editor, { at: path })}
className={css`
display: ${selected && focused ? 'inline' : 'none'};
position: absolute;
top: 0.5em;
left: 0.5em;
background-color: white;
`}
>
<Icon>delete</Icon>
</Button>
</div>
</div>
)
@@ -159,6 +181,20 @@ const initialValue: Descendant[] = [
},
],
},
{
type: 'paragraph',
children: [
{
text:
'You can delete images with the cross in the top left. Try deleting this sheep:',
},
],
},
{
type: 'image',
url: 'https://source.unsplash.com/zOwZKwZOZq8',
children: [{ text: '' }],
},
]
export default ImagesExample