diff --git a/.changeset/curly-ghosts-look.md b/.changeset/curly-ghosts-look.md new file mode 100644 index 000000000..a2adaced4 --- /dev/null +++ b/.changeset/curly-ghosts-look.md @@ -0,0 +1,5 @@ +--- +'slate-react': patch +--- + +Fixed crash on self-deleting void node diff --git a/packages/slate-react/src/components/editable.tsx b/packages/slate-react/src/components/editable.tsx index 2df1ec4bb..03ebe1849 100644 --- a/packages/slate-react/src/components/editable.tsx +++ b/packages/slate-react/src/components/editable.tsx @@ -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) + } + } } } }, diff --git a/site/examples/images.tsx b/site/examples/images.tsx index 30fb3964a..f406c734f 100644 --- a/site/examples/images.tsx +++ b/site/examples/images.tsx @@ -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 (
{children} -
+
{ box-shadow: ${selected && focused ? '0 0 0 3px #B4D5FF' : 'none'}; `} /> +
) @@ -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