diff --git a/packages/slate-react/src/plugins/core.js b/packages/slate-react/src/plugins/core.js index 1c58b3ce2..48b5397ca 100644 --- a/packages/slate-react/src/plugins/core.js +++ b/packages/slate-react/src/plugins/core.js @@ -163,7 +163,7 @@ function Plugin(options = {}) { const window = getWindow(e.target) const native = window.getSelection() const { state } = change - const { endBlock, endInline } = state + const { startKey, endKey, startText, endBlock, endInline } = state const isVoidBlock = endBlock && endBlock.isVoid const isVoidInline = endInline && endInline.isVoid const isVoid = isVoidBlock || isVoidInline @@ -187,6 +187,25 @@ function Plugin(options = {}) { attach = contents.childNodes[contents.childNodes.length - 1].firstChild } + // COMPAT: in Safari and Chrome when selecting a single marked word, + // marks are not preserved when copying. + // If the attatched is not void, and the startKey and endKey is the same, + // check if there is marks involved. If so, set the range start just before the + // startText node + if ((IS_CHROME || IS_SAFARI) && !isVoid && startKey === endKey) { + const hasMarks = startText.characters + .slice(state.selection.anchorOffset, state.selection.focusOffset) + .filter(char => char.marks.size !== 0) + .size !== 0 + if (hasMarks) { + const r = range.cloneRange() + const node = findDOMNode(startText) + r.setStartBefore(node) + contents = r.cloneContents() + attach = contents.childNodes[contents.childNodes.length - 1].firstChild + } + } + // Remove any zero-width space spans from the cloned DOM so that they don't // show up elsewhere when pasted. const zws = [].slice.call(contents.querySelectorAll('[data-slate-zero-width]'))