-
Notifications
You must be signed in to change notification settings - Fork 3.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Selection is null after editor loses focus #3412
Comments
Found a work around for this issue thanks to a kind developer on slack channel. Writing here in case anybody needs it. Store the selection value just before the editor loses focus. In my case it was when I clicked on input field, so I stored it just when dialog box opens. Similarly it can be applied to image upload, iframes or any action where editor loses focus.
|
Keeping on this, is there a way to actually keep it selected, as in highligting the text when losing focus ? |
I don't know if this is a bug or expected behaviour. But here if you have value of selection with you (which is |
Yeah, I am currently trying to do Transforms.setSelection with the value I got from the onBlur event , cant seem to make it work. Setting the editor.selection does seem to work correctly. I just need to find a way to highlight this and generalize the onBlur Event. I have found that this is checking the onSelectChange event from the dom to unselect , so my next thing is going to try to disable the unselection there , I will report back on my findings. So a quick work around, is to not allow the editor to be unselected - You can either run your own logic, or you can just "monkey patch" Transforms.deselect to be a empty function in the begginging of your app, this worked like a charm, and I can seem where this is actually being used on the internals of Slate apart from Focus/UnFocus. So so far this is my go to solution. |
You can get around this issue by setting readOnly to true before opening the link input or focusing outside the editor, and then setting back to false when done. However, this PR will need to be merged, since readOnly is broken right now. |
I also had success with monkey patching Transforms.deselect while my dialog is open, but it feels wrong :-) |
In particular manage selection and focus after inserting links. Once ianstormtaylor/slate#3412 is fixed we should be able to remove the wonky setTimeout(..., 200) bit here.
I wrote up a simple HOC using what @Lalitj03 posted if anyone's interested: |
It took me hours debugging before I read this issue and found out setting |
I am able to get around this issue by overriding |
@DianaLease I ran into some issues where the editor could then have it's selection state become out of sync with the content which will end up throwing some hard to debug exceptions |
Here is my solution to this problem:
Works well for all the basic commands my editor has: lists, numbers, formatting, headers, etc. |
The solution of @Bearz works, but it still removes the selection visually, which is problematic for some use cases. I want to change the font size for the selection via typing the font size into an input field, and for the user it is disturbing that the selection is no longer there visually, only "under the hood". |
But that was also the case in the previous version? |
Sorry, I did not mean that it worked differently in the prev pervious, I just meant that it is still a problem for some use cases. I think the safest solution is what you suggested, and draw a background explicitly when the focus is not there. |
Step 5 returns focus for me. I can continue to type exactly from the same place. Make sure that your command doesn't modify selection under the hood. If you split nodes or change blocks that might be a case. |
You can make it work even when splitting nodes, here is a basic example that works for me:
In FontColorPicker:
For some reason just running |
Consider setting CSS for toolbars buttons outside the slate editing area: |
@vsakos do you know why the cursor is put back to the start? I'm seeing this issue as well where inserting a new inline void element causes node splitting. I have to set my timeout pretty high (450ms) to make it work. |
I am getting the opposite problem, selection is not null when editor has lost focus. |
I needed to sort this out to make a Slate editor look and act like a textarea, which has a border div that can be clicked to focus the editor and needs to remember the selection. It's basically the same approach that @Bearz describes. Also important is the import clsx from 'clsx';
import React from 'react';
import { createEditor, Editor, Node, Transforms } from 'slate';
import { withHistory } from 'slate-history';
import { Editable, ReactEditor, Slate, withReact } from 'slate-react';
import './EditorTextArea.scss';
export interface EditorTextAreaProps {
value: Node[];
onChange: (value: Node[]) => void;
}
// @refresh reset
const EditorTextArea: React.FC<EditorTextAreaProps> = ({ value, onChange }) => {
const editor = React.useMemo(
() => withHistory(withReact(createEditor())),
[]
);
const [focused, setFocused] = React.useState(false);
const savedSelection = React.useRef(editor.selection);
const onFocus = React.useCallback(() => {
setFocused(true);
if (!editor.selection) {
Transforms.select(
editor,
savedSelection.current ?? Editor.end(editor, [])
);
}
}, [editor]);
const onBlur = React.useCallback(() => {
setFocused(false);
savedSelection.current = editor.selection;
}, [editor]);
const divRef = React.useRef<HTMLDivElement>(null);
const focusEditor = React.useCallback(
(e: React.MouseEvent) => {
if (e.target === divRef.current) {
ReactEditor.focus(editor);
e.preventDefault();
}
},
[editor]
);
return (
<div
ref={divRef}
className={clsx('editor-textarea', { focused })}
onMouseDown={focusEditor}>
<Slate editor={editor} value={value} onChange={onChange}>
<Editable onFocus={onFocus} onBlur={onBlur} />
</Slate>
</div>
);
};
export default EditorTextArea; |
Hey guys, what if you use |
Works like charm. Thanks for sharing!
onMouseDown doesn't lose highlight but lose focus. I am not sure why. |
Like others in this thread, I was also caught by the unexpected behaviour of basically,if you need to regain focus with the previous selection, use |
For step 1. If I put the buttons outside , how can I use |
@raitucarp I don't have a project set up to try it out, but most likely keeping the ref and passing it to a ButtonComponent as a prop should do a trick. Example code (may contain errors as I haven't written JSX in forever):
|
Thanks, totally makes sense now. My text editor is too way complicated, involves popover triggering on a button click, and causes my text editor to trigger get on blur but I want to keep my button change the icon when the block is active, sometimes I want to give up. But your post helps me to understand more.. Thank you... |
Thank you so much! |
Has any one found a solution to keeping the previous 'selected' highlighted while pressing buttons outside of ? Finding this is a huge problem, as I would like to have user type in a font while the text is still selected -- 'highlighted'. This helps with storing and then actually changing the selected but cannot keep highlighted:
And this causes the new 'selected' value to not be the point where the focus begins overriding the highlighted selected to the singular anchor where the focus started, (so I.e. I cannot click 'italics' button twice with the same selected text:
` Anyone else still having this problem? Or have a good solution for similar use cases/issues? would be a life saver. |
I also added a |
One alternative solution: When focus leaves the editor, wrap the current selection in a fake custom selection node. Then, instead of relying on We did this in our code base and it works well; it allows you to implement a floating toolbar and have inline inputs next to your editor. I'm hoping to write an article/tutorial soon to clarify how all of this works and what the code looks like. But that's the basic idea: Just like you have other inline nodes (hyperlinks and whatever else), you can also mock up a selection node that doesn't get serialized/deserialized and is only a run-time helper. |
I was able to keep the selected text highlighted when clicking on a toolbar button by using the following prop on
That doesn't stop the editor from getting set to |
Still not fixed? |
I believe this has been fixed actually, though I'm not sure in which commit or release. See this comment on Slack, from when I asked related questions on the Slate Slack. What may still be an issue for some users is that |
@AleksandrHovhannisyan |
@davevilela Sorry for the tease, I know that's not a ton of info to go off of. I'm still hoping I can get around to writing a blog post about it one of these days. I know Notion does something very similar in its editor; when you highlight some text and try to insert a hyperlink, they insert a fake blue wrapper span styled to look like a regular selection, and then they delete it afterwards. |
@AleksandrHovhannisyan hey, I put some time into researching and going through other people's code and came up with this prototype: type EditorWithPrevSelection<V extends Value = Value> = PlateEditor<V> & {
prevSelection: BaseRange | undefined;
};
export const createFakeSelectionPlugin = createPluginFactory({
key: FAKE_SELECTION_MARK,
isLeaf: true,
handlers: {
onBlur: (editor: EditorWithPrevSelection<Value>) => (event) => {
event.preventDefault();
const currentSelection = editor.selection;
const hasSelection = !!currentSelection && isSelectionExpanded(editor);
if (hasSelection) {
setMarks(editor, { [FAKE_SELECTION_MARK]: true });
editor.prevSelection = editor.selection;
}
},
onFocus: (editor: EditorWithPrevSelection<Value>) => (event) => {
event.preventDefault();
const { prevSelection } = editor;
if (prevSelection) {
Transforms.select(editor as any, prevSelection);
editor.prevSelection = undefined;
removeMark(editor, {
key: FAKE_SELECTION_MARK,
shouldChange: false,
mode: 'all',
});
}
},
},
component: withProps(StyledLeaf, {
as: FAKE_SELECTION_MARK,
styles: {
root: {
background: 'var(--chakra-colors-textSelect)',
},
},
}),
}); hope this helps anyone that comes across this issue! edit: i'm using plate for my plugin system |
Do you want to request a feature or report a bug?
Bug
What's the current behavior?
Current behavior is that when you click into the toolbar or out of the document the editor's selection becomes null.
https://codesandbox.io/s/fervent-bouman-ju71u?fontsize=14&hidenavigation=1&theme=dark
Tested on Firefox, Safari and Chrome although Firefox has different behavior. Firefox sometimes sets the cursor position to the end of the text in the editor depending on how you focus out of the editor.
Slate: 0.57.1
Browser: Chrome / Safari / Firefox
OS: Mac
What's the expected behavior?
Focus out shouldn't erase editor selection.
Changes to Example Site To Produce Behavior
In order to test this we forked the rich text example and made sure the toolbar style buttons did not disable on focus out. Then we used the
ReactEditor.focus
method in theMarkdownButton
component'sonMouseDown
handler in therichtext.js
file.The text was updated successfully, but these errors were encountered: