From 8e4120ae315151705152e62944737ca4f62ad446 Mon Sep 17 00:00:00 2001 From: Githoniel Date: Mon, 16 Aug 2021 19:42:26 +0800 Subject: [PATCH] fix: insert new node in advance to avoid ime double input with editor marks (#4451) * fix: insert new node in advance to avoid ime double input * chore: add changeset * refactor: minor refator as review --- .changeset/old-bees-design.md | 5 ++ .../slate-react/src/components/editable.tsx | 57 ++++++++++++++++++- 2 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 .changeset/old-bees-design.md diff --git a/.changeset/old-bees-design.md b/.changeset/old-bees-design.md new file mode 100644 index 000000000..ec9aaff03 --- /dev/null +++ b/.changeset/old-bees-design.md @@ -0,0 +1,5 @@ +--- +'slate-react': patch +--- + +fix IME double input with editor mark diff --git a/packages/slate-react/src/components/editable.tsx b/packages/slate-react/src/components/editable.tsx index 8788b32a8..2fe8a019c 100644 --- a/packages/slate-react/src/components/editable.tsx +++ b/packages/slate-react/src/components/editable.tsx @@ -132,6 +132,7 @@ export const Editable = (props: EditableProps) => { const state = useMemo( () => ({ isComposing: false, + hasInsertPrefixInCompositon: false, isDraggingInternally: false, isUpdatingSelection: false, latestElement: null as DOMElement | null, @@ -724,6 +725,23 @@ export const Editable = (props: EditableProps) => { ) { Editor.insertText(editor, event.data) } + + if (editor.selection && Range.isCollapsed(editor.selection)) { + const leafPath = editor.selection.anchor.path + const currentTextNode = Node.leaf(editor, leafPath) + if (state.hasInsertPrefixInCompositon) { + state.hasInsertPrefixInCompositon = false + Editor.withoutNormalizing(editor, () => { + // remove Unicode BOM prefix added in `onCompositionStart` + const text = currentTextNode.text.replace(/^\uFEFF/, '') + Transforms.delete(editor, { + distance: currentTextNode.text.length, + reverse: true, + }) + Transforms.insertText(editor, text) + }) + } + } } }, [attributes.onCompositionEnd] @@ -746,9 +764,42 @@ export const Editable = (props: EditableProps) => { hasEditableTarget(editor, event.target) && !isEventHandled(event, attributes.onCompositionStart) ) { - const { selection } = editor - if (selection && Range.isExpanded(selection)) { - Editor.deleteFragment(editor) + const { selection, marks } = editor + if (selection) { + if (Range.isExpanded(selection)) { + Editor.deleteFragment(editor) + return + } + const inline = Editor.above(editor, { + match: n => Editor.isInline(editor, n), + mode: 'highest', + }) + if (inline) { + const [, inlinePath] = inline + if (Editor.isEnd(editor, selection.anchor, inlinePath)) { + const point = Editor.after(editor, inlinePath)! + Transforms.setSelection(editor, { + anchor: point, + focus: point, + }) + } + } + // insert new node in advance to ensure composition text will insert + // along with final input text + // add Unicode BOM prefix to avoid normalize removing this node + if (marks) { + state.hasInsertPrefixInCompositon = true + Transforms.insertNodes( + editor, + { + text: '\uFEFF', + ...marks, + }, + { + select: true, + } + ) + } } } },