Add support for preventing native character insertion #453
Add support for preventing native character insertion #453
Conversation
@@ -349,6 +359,19 @@ static setInlineStyleOverride(inlineStyleOverride: DraftInlineStyle): EditorStat | |||
Returns a new `EditorState` object with the specified `DraftInlineStyle` applied | |||
as the set of inline styles to be applied to the next inserted characters. | |||
|
|||
### forceSelection |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll fix this and force push.
9cabb91
to
b3d0eb6
Compare
Come to think of it, this probably doesn't need to be re-set every time Instead, I think it could be set when providing the initial |
FWIW – I considered an alternative approach which allowed setting a new handleBeforeNativeInput(chars: string): boolean This would be called much like Ultimately, I was ignoring the input |
Once you set this, it's on forever? Does it make sense to automatically set it to false after an update? |
Currently, whatever value is set remains set until it is explicitly changed. I'm not at all opposed to that changing.
@spicyj where do you think that should happen? |
Not sure, sorry. Just seemed weird from a first glance. |
@hellendag (and @spicyj) – if this at least inspires a more desirable solution from either of you I'd be happy to work on that if I could get some direction. |
@paulyoung What about having a fourth argument in I wonder what implications this has for the undo/redo history. Have you tried them in combination with this change? |
@nikgraf – thanks for the input. I really appreciate it.
With the current changeset, it does appear that things aren't fully taken care of. It seems that:
I'll explore that tomorrow. Thanks again for the idea! |
To clarify – ⌘ + z doesn't do anything |
I just pushed a couple of commits in line with @nikgraf's comments. I still had to update the original code example to update the selection state: onChange(editorState) {
const contentState = editorState.getCurrentContent();
const selectionState = editorState.getSelection();
const blockMap = contentState.getBlockMap();
const newBlockMap = blockMap.map((contentBlock) => {
// perform some updates here
return contentBlock;
});
const newContentState = contentState.set('blockMap', newBlockMap);
const newEditorState = EditorState.push(editorState, newContentState, 'insert-fragment', true);
this.setState({
editorState: EditorState.acceptSelection(newEditorState, selectionState),
});
} This almost works as expected, the only exceptions being a couple of anomalies with the cursor position on undo/redo. If anyone could take a look and has any advice, I'd really appreciate it. Once again, my use case is described in #448 (comment) |
@hellendag – I'd love to keep this going and arrive at an acceptable solution, but think I may need some help/input from you (or someone who has more experience with Draft.js) to get there. If there's any way I can make that easy for you, or you have any suggestions, please let me know. |
I don't think this belongs on |
It seems similar to forceSelection to me – don't you think? |
Interesting point. A question on usage, whether it's a state value or a prop: how will I know when to set this? I need to set it before
This actually sounds like a pretty good approach to me. The function prop doesn't handle the insertion, but it determines whether the value should be allowed natively. So that way, rather than setting a boolean value in the overall state of the editor, you would essentially perform filtering on values as they arrive, or use some other information to determine how to handle the character. A contrived example: allowNativeInsertion(chars: string): boolean {
if (chars === 'c') {
// we want to handle `c` manually, no native insertion allowed
return false;
}
return true;
}
// within your `Editor`
<Editor
...
allowNativeInsertion={allowNativeInsertion}
editorState={editorState}
/>
// within `onBeforeInput`
if (
!this.props.allowNativeInsertion(chars) ||
...
) {
// handle manually
return;
} This seems okay to me, and it gives you an opportunity to selectively decide how to manage the incoming insertion. |
Thanks for the thoughtful replies! I'll go back and try this approach this afternoon. |
I've removed the functionality around this that I added to The way this is called in This appears to work well except for undo/redo again. I attempted to handle this in 30791d6 via Now, in conjunction with the code in my original comment #453 (comment), items on the |
I may have bandwidth to take a stab at fixing undo/redo with the latest changes soon. If anyone has any ideas, I'd love to hear them! |
b46a866
to
054f2e2
Compare
I took a quick look at this again and I'm having a bit of trouble seeing how to affect undo/redo now that |
This issue comes up a lot in our Slack. Would be nice to have this implemented soon. |
@paulyoung Would you mind clarifying a bit what the undo/redo issues are for your current solution? When you perform an undo, what happens? Is the issue that the I appreciate the simplicity of this change, so it would be great to get this to work. :) |
@hellendag I decided to first examine the undo stack before applying the changes in this pull request. This appears to exhibit the same behavior, so while it doesn't seem like a problem caused by the code I've introduced it's a problem that needs to be addressed somehow nonetheless. Below is the _onChange(editorState) {
const contentState = editorState.getCurrentContent();
const selectionState = editorState.getSelection();
const blockMap = contentState.getBlockMap();
const newBlockMap = blockMap.map((contentBlock) => {
// perform some updates here
return contentBlock;
});
const newContentState = contentState.set('blockMap', newBlockMap);
const newEditorState = EditorState.push(editorState, newContentState, 'insert-fragment', true);
console.log(JSON.stringify(newEditorState.toJS().undoStack.map((x) => x.blockMap), null, 2));
this.setState({
editorState: EditorState.acceptSelection(newEditorState, selectionState),
});
} If there's a way that I can change this to "fix" the undo/redo stack that would be great, although I think a baked-in solution that "just works" would be nice. Here is what was logged for each action (expand to view):
|
It seems to me that since the approach taken with the latest changes doesn't support a way to address the issues with the undo/redo stack, I should revert to the |
Still not completely sure I understand, but it seems like in the logged output, for each step there is an extra |
I'm going to get back to this soon, I promise 🙇 |
Quick update on this – discarding the top of the undo stack does appear to address the issues I was having with duplicate characters, when paired with this changes in this branch. I still can't get undo/redo to work, although that appears to be a problem with the way I'm handling |
My #667 should fix this cleanly so let's go with that. |
Oh, awesome @spicyj! Would love to see this land soon! |
@paulyoung I still would like this PR to go through. Half of the point of draftjs is that contenteditable is essentially unspecced. I am very hesitant to rely on the browser to do the right thing here. I would prefer to at the very minimum give the ability for the caller to disable native behavior. |
@hellendag this intends to address the issue we discussed in #427 and #448.
The intended use is something like this:
Please review and let me know if you have any feedback.
Thanks!