From 8a2a60b052dd666ef4ec128863a56b251aec8ea8 Mon Sep 17 00:00:00 2001 From: Ulion Date: Thu, 1 Apr 2021 10:06:30 +0800 Subject: [PATCH] Fix normalizeDOMPoint to do better job. (#4048) --- packages/slate-react/src/utils/dom.ts | 36 +++++++++++++++++++++------ 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/packages/slate-react/src/utils/dom.ts b/packages/slate-react/src/utils/dom.ts index 860e27bdc..7d4ae3a36 100644 --- a/packages/slate-react/src/utils/dom.ts +++ b/packages/slate-react/src/utils/dom.ts @@ -107,16 +107,21 @@ export const normalizeDOMPoint = (domPoint: DOMPoint): DOMPoint => { // If it's an element node, its offset refers to the index of its children // including comment nodes, so try to find the right text child node. if (isDOMElement(node) && node.childNodes.length) { - const isLast = offset === node.childNodes.length - const direction = isLast ? 'backward' : 'forward' - const index = isLast ? offset - 1 : offset - node = getEditableChild(node, index, direction) + let isLast = offset === node.childNodes.length + let index = isLast ? offset - 1 : offset + ;[node, index] = getEditableChildAndIndex( + node, + index, + isLast ? 'backward' : 'forward' + ) + // If the editable child found is in front of input offset, we instead seek to its end + isLast = index < offset // If the node has children, traverse until we have a leaf node. Leaf nodes // can be either text nodes, or other void DOM nodes. while (isDOMElement(node) && node.childNodes.length) { const i = isLast ? node.childNodes.length - 1 : 0 - node = getEditableChild(node, i, direction) + node = getEditableChild(node, i, isLast ? 'backward' : 'forward') } // Determine the new offset inside the text node. @@ -138,15 +143,15 @@ export const hasShadowRoot = () => { } /** - * Get the nearest editable child at `index` in a `parent`, preferring + * Get the nearest editable child and index at `index` in a `parent`, preferring * `direction`. */ -export const getEditableChild = ( +export const getEditableChildAndIndex = ( parent: DOMElement, index: number, direction: 'forward' | 'backward' -): DOMNode => { +): [DOMNode, number] => { const { childNodes } = parent let child = childNodes[index] let i = index @@ -179,9 +184,24 @@ export const getEditableChild = ( } child = childNodes[i] + index = i i += direction === 'forward' ? 1 : -1 } + return [child, index] +} + +/** + * Get the nearest editable child at `index` in a `parent`, preferring + * `direction`. + */ + +export const getEditableChild = ( + parent: DOMElement, + index: number, + direction: 'forward' | 'backward' +): DOMNode => { + const [child] = getEditableChildAndIndex(parent, index, direction) return child }