From 79eee6b378e4a3baa8eadc894bfedd55767307e0 Mon Sep 17 00:00:00 2001 From: Githoniel Date: Thu, 20 Aug 2020 23:43:16 +0800 Subject: [PATCH] fix inconsistent render reversed selection (#3804) * fix inconsistent render reversed selection * fix type error * add comment for setReverseDomSelection * add comment for setReverseDomSelection * add comment for toDOMRange --- .../slate-react/src/components/editable.tsx | 7 ++++++- .../slate-react/src/plugin/react-editor.ts | 5 +++++ packages/slate-react/src/utils/dom.ts | 21 +++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/packages/slate-react/src/components/editable.tsx b/packages/slate-react/src/components/editable.tsx index df6a86e81..e6fbc0e71 100644 --- a/packages/slate-react/src/components/editable.tsx +++ b/packages/slate-react/src/components/editable.tsx @@ -33,6 +33,7 @@ import { isDOMText, DOMStaticRange, isPlainTextOnlyPaste, + setReverseDomSelection, } from '../utils/dom' import { EDITOR_TO_ELEMENT, @@ -184,7 +185,11 @@ export const Editable = (props: EditableProps) => { const newDomRange = selection && ReactEditor.toDOMRange(editor, selection) if (newDomRange) { - domSelection.addRange(newDomRange!) + if (Range.isBackward(selection!)) { + setReverseDomSelection(newDomRange, domSelection) + } else { + domSelection.addRange(newDomRange!) + } const leafEl = newDomRange.startContainer.parentElement! scrollIntoView(leafEl, { scrollMode: 'if-needed', diff --git a/packages/slate-react/src/plugin/react-editor.ts b/packages/slate-react/src/plugin/react-editor.ts index 250839857..4f26981e4 100644 --- a/packages/slate-react/src/plugin/react-editor.ts +++ b/packages/slate-react/src/plugin/react-editor.ts @@ -269,6 +269,11 @@ export const ReactEditor = { /** * Find a native DOM range from a Slate `range`. + * + * Notice: the returned range will always be ordinal regardless of the direction of Slate `range` due to DOM API limit. + * + * there is no way to create a reverse DOM Range using Range.setStart/setEnd + * according to https://dom.spec.whatwg.org/#concept-range-bp-set. */ toDOMRange(editor: ReactEditor, range: Range): DOMRange { diff --git a/packages/slate-react/src/utils/dom.ts b/packages/slate-react/src/utils/dom.ts index 0736bd4d1..77557f715 100644 --- a/packages/slate-react/src/utils/dom.ts +++ b/packages/slate-react/src/utils/dom.ts @@ -174,3 +174,24 @@ export const getPlainText = (domNode: DOMNode) => { return text } + +/** + * there is no way to create a reverse DOM Range using Range.setStart/setEnd + * according to https://dom.spec.whatwg.org/#concept-range-bp-set. + * Luckily it's possible to create a reverse selection via Selection.extend + * + * Note: Selection.extend is not implement in any version of IE (up to and including version 11) + */ + +export const setReverseDomSelection = ( + domRange: DOMRange, + domSelection: Selection +) => { + const newRange = domRange.cloneRange() + // collapses the range to end + newRange.collapse() + // set both anchor and focus of the selection to domRange's focus + domSelection.addRange(newRange) + // moves the focus of the selection to domRange's anchor + domSelection.extend(domRange.startContainer, domRange.startOffset) +}