draft-js
draft-js copied to clipboard
OS X "Add period with double-space" feature breaks Editor if invoked after a decorator
Reproducible here: https://jsfiddle.net/3o2jnf5k/
Steps to reproduce:
1 - Create a decorated block of text, e.g.: type #tweet
in editor
2 - Trigger "Add period with double-space" functionality by double tapping spacebar
Result: Editor is left in a funky state
I'm seeing a similar issue when I render a custom link component. I've also noticed the issue in the demo example on https://draftjs.org/
Steps to reproduce:
- add some text into the editor
- add an inline style
- Trigger "Add period with double-space" functionality by double tapping spacebar
Result: Editor is left in a funky state
If you then try to edit the content it throws :
Error: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
Currently, I fighting with the same issue. I found that this is related to the OSX keyboard setting. When I turned off "Add full stop with double-space", the issue disappeared.
Anyway, this is not a solution, it is just a clue. I am still looking for a solution.

I was able to disable it programmatically in the end by using something similar to the following:
function replaceText(
editorState,
text,
inlineStyle,
forceSelection,
) {
const contentState = Modifier.replaceText(
editorState.getCurrentContent(),
editorState.getSelection(),
text,
inlineStyle,
);
return EditorState.push(
editorState,
contentState,
'insert-characters',
forceSelection,
);
}
function isASCIIChar(str) {
return /^\S+$/.test(str);
}
const handleBeforeInput = (str, newState) => {
if (lastKeyPressed === ' ' && !isASCIIChar(str)) {
lastKeyPressed = null;
onChange(replaceText(newState, ' ', newState.getCurrentInlineStyle(), true));
return 'handled';
}
if (str === ' ') {
lastKeyPressed = str;
return 'not-handled';
}
...
};
Ah yes, unfortunately I tracked the fix to this error to something that has to be changed in React too, so it'll take a while. It's on the radar though.
@mrkev Do you know why this happens? Can you explain that? If you don't have the time it's OK, I am just curious. Have a nice day
@FilipMessa I think it's probably related to this, since it's a text replacement and it happens when there's decorators, which add DOM nodes (leafs): https://github.com/facebook/draft-js/issues/2171#issuecomment-631749909
I just want to share my findings that is not yet complete.
I was looking into the component/handlers/edit/editOnInput.js
and found that adding a space after double whitespaces has a weird behavior in the underlying editorState's content.
In normal case, the DOM text will match with the model text (https://github.com/facebook/draft-js/blob/fb728fde4f041270f2234263a8572a8fe4d50258/src/component/handlers/edit/editOnInput.js#L128)
But, the model text with the period after the two whitespaces have mismatched text
Attaching screenshot for debug details:
My console code: console.log('here', e.nativeEvent, '|' + block.getText() + '|', '|' + domText + '|', '|' + modelText + '|');
You can see the logs for the second space I inserted produced an expected content in the DOM text, but the model text has an extra space after the text.
It looks like during the given second whitespace, the editorState given to editOnInput
passes both the first whitespace + the result of the second space (a period and a leading whitespace)
I'm not sure why there is an "apply-entity" change type after the second space
Then, I'm also not sure why adding another character makes the model text return to the correct one.
Edit: we may be able to check if the input event is inserting a .
and replace the last white space with .
.
Adding more details on my findings at my prior post, I found that the content is also handled by the handleBeforeInput
.
So, to "disable" OS's behavior in replacing 2 whitespaces (
) with a period and a whitespace (.
), we handle the input prior to handling the input by checking if the event is trying to insert a special character (.
) and replace it with a whitespace instead.
handleBeforeInput={(chars, editorState, eventTimestamp) => {
if (chars === '. ') {
const currentSelection = editorState.getSelection();
this.setState({
editorState: EditorState.set(
editorState,
{
currentContent: Modifier.replaceText(
editorState.getCurrentContent(),
currentSelection,
// or
// currentSelection.merge({
// anchorOffset: currentSelection.getAnchorOffset() - 1
// }),
// '. '
' '
)
}
)
})
return 'handled';
}
return 'not-handled';
}}
I hope it helps
Edit: The above is a workaround. A more permanent fix should be done internally. This is my attempt to fix it - https://github.com/facebook/draft-js/pull/2588/files
Does anyone knows how to fix the spacing/double spacing issue on draftjs ? I've spend couple of days trying to figure how to fix it but no luck. I saw couple suggestions here but this still did not fix my problem.
Scenario one and steps to reproduce.
- Go to https://codesandbox.io/s/elegant-chatelet-1ozdw?file=/src/LinkAndUnlinkText/index.js.
- You will see default populated link on styled editor (looks like text field) and click/focus on the editor at end of the text try hit space keyboard one or try to do double space it removes the link then crashes the app. Visual test case see below
Scenario two and steps to reproduce.
- Go to https://codesandbox.io/s/elegant-chatelet-1ozdw?file=/src/LinkAndUnlinkText/index.js. and comment out line 393 function called handleBeforeInput and uncomment line 394 function called handleBeforeInput={(string, editorFromParam) => handleSpaceIssue(string, editorFromParam)}.
- Then click on editor/text field and try to type space at the end of the text. See below for visual test case.
Second scenario works when handling manually but for some reason the UI can not detect the manual changes even after editorState update (see screenshot or open the dev console in sandbox). I would appreciate if someone advice anything I am running out of options. Thanks
Any update on this ?