slate
slate copied to clipboard
Rich Text example: 'select all' and 'delete' does not delete everything when there is a list
Do you want to request a feature or report a bug?
A bug.
What's the current behavior?
On the current "Rich Text" example on https://www.slatejs.org/#/rich-text the following steps are causing an unexpected behavior:
- Delete the default contents
- Create a new unordered list
- Press 'Enter'
- Click on the 'unordered list' button again
- Select all (with CTRL-A)
- Press 'Delete'
The editor's contents are not entirely removed, instead the unordered list is kept and the cursor is still indented, without any list items.
What's the expected behavior?
The entire content should be deleted.
This bug still exists, and there doesn't seem to be an easy way to get around it either.
Possible duct tape fix (haven't tested it): enforce via schema that first element is paragraph (or other).
I'm working on an editor built similar to the rich text example, so I might test if the same issue occurs there and attempt a fix.
The same issue still occurs in mine. This is after replicating the steps twice. You'll notice there are still two blocks of type ordered list
.
I've tried using editor.moveToRangeOfDocument().delete()
which did work to an extent...I attached it to a button. After clicking once, it didn't seem to activate, but after the 2nd and 3rd clicks they worked. However, upon examining the document, it also seemed to delete the required child block
node, essentially leaving the editor in an unusable state.
The most effective quick-fix to this problem is to add a button or command to reset the editor to a default value. That way if it bugs out, you can return the editor to a usable state.
One possible fix is to keep track of both Ctrl+A and Delete usages. If Delete is used after select all Ctrl+A then you can use setBlocks(DEFAULT_NODE)
to have it prevent the stacking in the first place. It's not the most efficient fix as it might have some unintended behaviours in rare cases, but I can confirm that it does work with this particular rich text example (and perhaps other similar list implementations).
const DEFAULT_NODE = "paragraph";
const isDeleteHotKey = isKeyHotkey("delete");
const isSelectAllHotKey = isKeyHotkey("mod+a");
//using React hooks
function Editor() {
const [isAllSelected, setAllSelected] = useState(false);
...
const onKeyDown = (event, editor, next) => {
...
} else if (isSelectAllHotKey(event)) {
setAllSelected(!isAllSelected); //Toggle selected flag for Ctrl+A
return next();
} else if (isDeleteHotKey(event)) {
if (isAllSelected) {
editor.setBlocks(DEFAULT_NODE);
setAllSelected(false);
return next();
} else {
return next();
}
} else {
if (isAllSelected) setAllSelected(false); //Ensure isAllSelected is false on other key presses.
return next();
}
}
}
I had a similar issue and I fixed it with user-select: none
.
const Uneditable: FunctionComponent = props => {
return (
<>
<div contentEditable={false}>{props.children}</div>
{/*
To fix errror: "IndexSizeError: Failed to execute 'getRangeAt'
on 'Selection': 0 is not a valid index." and some others.
*/}
<style jsx>{`
div {
user-select: none;
}
`}</style>
</>
);
};
Went down the same path as @dons20 - here is the updated code to work with Slate 0.50+
import { Transforms, .. } from 'slate';
..
const isSelectAllHotkey = isHotkey('mod+a');
const isDeleteHotkey = isHotkey('backspace');
..
const [isAllSelected, setAllSelected] = React.useState(false);
..
onKeyDown={event => {
if (isDeleteHotkey(event)) {
if (isAllSelected) {
Transforms.delete(editor);
Transforms.setNodes(editor, { type: 'paragraph' });
setAllSelected(false);
return;
}
}
if (isSelectAllHotkey(event)) {
setAllSelected(!isAllSelected);
} else {
setAllSelected(false);
}
While not ideal, it fixed the bug for me 🤷♂️
This reproduced for use when using tables. Can reproduce here: https://www.slatejs.org/examples/tables
- delete everything after the table
- select all
- delete
Now we're always in a single td
(without table
, tr
etc.) and trying to break out of it just adds more td
s.
So to solve it we added this to the editor.insertBreak()
:
if (selection) {
const [cell] = Editor.nodes(editor, {
match: (n) => !Editor.isEditor(n) && SlateElement.isElement(n) && n.type === 'table-cell',
});
if (cell) {
const [, cellPath] = cell;
const start = Editor.start(editor, cellPath);
const end = Editor.end(editor, cellPath);
if (Point.equals(selection.anchor, end) || Point.equals(selection.anchor, start)) {
Transforms.setNodes(editor, { type: 'container' });
}
}
}
insertBreak();
Hope this might help others
I used Transforms.select(editor, [])
and it work fine for me
https://docs.slatejs.org/concepts/03-locations