Open idevelop opened 4 years ago
Almost similar problems with you are solved in this way. I hope there is a better solution. The following is my way;
Transforms.select(editor, {
path: [p1, p2, p3 + 1, 0],
offset: 2,
});
This error also happens when editor.selection
is null
throughout the lifecycle of the editor object. The workaround mentioned by @idevelop works for me for now though!
Same problem here.
My editor breaks when state is rested from more than one paragraph to empty via value
prop in <Slate>
component from slate-react
.
Is this will be somehow solved in future releases or @idevelop workaround is all we have for now?
@chomamateusz There used to be set_value
operation for this particular use-case but now you might be better off recreating the editor component when this happens so that you don't hold on to previous information. It would be nice if there was a reliable way to reset the editor without having to recreate the component though.
I see this issue is still open. Any update about this issue? Do we have a better way to solve this?
We love Slate at Zapier, but run into this issue as well, when a user undo's pasting a value that results in nodes with an empty leaf text node. This is how we can reproduce:
children
being:[
{
"children": [
{
"text": ""
}
],
"type": "paragraph"
}
]
[
{
"type": "paragraph",
"children": [
{
"text": "sdfsdfsdfsdf"
},
{
"type": "mapped-field",
"value": "166003157__id",
"children": [
{
"text": ""
}
]
},
{
"text": ""
},
{
"type": "mapped-field",
"value": "166003157__hello",
"children": [
{
"text": ""
}
]
},
{
"text": ""
}
]
}
]
You'll get:
This happens after the 2nd of these inverseOps
:
[
{
"type": "set_selection",
"properties": {
"anchor": {
"path": [
0,
0
],
"offset": 0
},
"focus": {
"path": [
0,
0
],
"offset": 0
}
},
"newProperties": {
"anchor": {
"path": [
0,
4
],
"offset": 0
},
"focus": {
"path": [
0,
4
],
"offset": 0
}
}
},
{
"type": "insert_node",
"path": [
0,
2
],
"node": {
"text": ""
}
},
{
"type": "set_selection",
"properties": {
"anchor": {
"path": [
0,
5
],
"offset": 0
},
"focus": {
"path": [
0,
5
],
"offset": 0
}
},
"newProperties": {
"anchor": {
"path": [
0,
2
],
"offset": 0
},
"focus": {
"path": [
0,
2
],
"offset": 0
}
}
},
{
"type": "remove_node",
"path": [
0,
5
],
"node": {
"text": ""
}
},
{
"type": "remove_node",
"path": [
0,
4
],
"node": {
"type": "mapped-field",
"value": "166003157__hello",
"children": [
{
"text": ""
}
]
}
},
{
"type": "insert_text",
"path": [
0,
3
],
"offset": 0,
"text": "{{166003157__hello}}"
},
{
"type": "set_selection",
"properties": {
"anchor": {
"path": [
0,
2
],
"offset": 0
},
"focus": {
"path": [
0,
2
],
"offset": 0
}
},
"newProperties": {
"anchor": {
"path": [
0,
3
],
"offset": 20
},
"focus": {
"path": [
0,
3
],
"offset": 20
}
}
},
{
"type": "remove_node",
"path": [
0,
2
],
"node": {
"text": ""
}
},
{
"type": "remove_node",
"path": [
0,
1
],
"node": {
"type": "mapped-field",
"value": "166003157__id",
"children": [
{
"text": ""
}
]
}
},
{
"type": "merge_node",
"path": [
0,
1
],
"position": 12,
"properties": {}
},
{
"type": "insert_text",
"path": [
0,
0
],
"offset": 12,
"text": "{{166003157__id}}"
},
{
"type": "remove_text",
"path": [
0,
0
],
"offset": 0,
"text": "sdfsdfsdfsdf{{166003157__id}}{{166003157__hello}}"
}
]
This plugin worked for me:
import { Editor, Element, Node, Transforms } from 'slate';
function nodeHasNoText(node: Node) {
return Node.string(node) === '';
}
export const withDeleteCheck = (editor: Editor) => {
const { deleteBackward, deleteForward } = editor;
function isEditorEmpty() {
return editor.children.length === 0 || (editor.children.length === 1 && Node.string(editor.children[0]) === '');
}
function ensureNotEmpty() {
if (isEditorEmpty()) {
Transforms.insertNodes(editor, { type: 'paragraph', children: [{ text: '' }] });
}
}
editor.deleteBackward = (unit) => {
if (!isEditorEmpty()) {
deleteBackward(unit);
return;
}
// OPTIONAL:
removeEmptyNodes();
};
editor.deleteForward = (unit) => {
if (!isEditorEmpty()) {
deleteForward(unit);
return;
}
// OPTIONAL:
removeEmptyNodes();
};
// OPTIONAL:
const removeEmptyNodes = () => {
for (const [node, path] of Node.descendants(editor, { reverse: true })) {
if (Element.isElement(node) && nodeHasNoText(node)) {
if (isEditorEmpty()) {
ensureNotEmpty();
return;
}
Transforms.removeNodes(editor, { at: path });
}
}
};
return editor;
};
We've been having this issue for awhile, but seems to be a different root cause.
We have a reorderable report (similar to Notion) but if a state change is triggered right before the Transform.moveNodes
is called, it seems to result in a slate render being initiated, but only completing after the transform is finished. Which, in our case, means it would try to render a child that had already been moved.
We defer state changes until after committing the transforms and it seems to be OK. This also only was happening with a report with greater than two levels of depth.
I'm integrating the code examples into our app and I'm hitting an issue that might be a bug, or me not understanding how to correctly reset the editor state.
Here's a quick summary of the React structure of our Composer component:
This works fine when the value in the editor is simple, but when the editor has a value that is deeply nested, like a list with one list item:
... I get this error in the console after clearing the editor:
It seems that, even though the selection range was set to empty, it still holds on to the depth information, the fact that the focus was on a node that was 3 levels deep in the value, so I'm guessing either I have to reset the entire path somehow, or this is a bug.
I managed to fix this by changing the clear transform to:
I'm curious if there's another, more straightforward way to use the Editor API to get the same result.