diff --git a/packages/slate/src/changes/at-range.js b/packages/slate/src/changes/at-range.js index c40161a43..cafaf8535 100644 --- a/packages/slate/src/changes/at-range.js +++ b/packages/slate/src/changes/at-range.js @@ -948,7 +948,26 @@ Changes.setBlockAtRange = (change, range, properties, options = {}) => { const { document } = value const blocks = document.getBlocksAtRange(range) - blocks.forEach(block => { + const { startKey, startOffset, endKey, endOffset, isCollapsed } = range + const isStartVoid = document.hasVoidParent(startKey) + const startBlock = document.getClosestBlock(startKey) + const endBlock = document.getClosestBlock(endKey) + + // Check if we have a "hanging" selection case where the even though the + // selection extends into the start of the end node, we actually want to + // ignore that for UX reasons. + const isHanging = + isCollapsed == false && + startOffset == 0 && + endOffset == 0 && + isStartVoid == false && + startKey == startBlock.getFirstText().key && + endKey == endBlock.getFirstText().key + + // If it's a hanging selection, ignore the last block. + const sets = isHanging ? blocks.slice(0, -1) : blocks + + sets.forEach(block => { change.setNodeByKey(block.key, properties, { normalize }) }) } diff --git a/packages/slate/test/changes/at-current-range/set-block/across-blocks.js b/packages/slate/test/changes/at-current-range/set-block/across-blocks.js index f8aa5ad34..ea5b47427 100644 --- a/packages/slate/test/changes/at-current-range/set-block/across-blocks.js +++ b/packages/slate/test/changes/at-current-range/set-block/across-blocks.js @@ -13,7 +13,7 @@ export const input = ( word - another + another @@ -26,7 +26,7 @@ export const output = ( word - another + another diff --git a/packages/slate/test/changes/at-current-range/set-block/hanging-selection.js b/packages/slate/test/changes/at-current-range/set-block/hanging-selection.js new file mode 100644 index 000000000..08371583c --- /dev/null +++ b/packages/slate/test/changes/at-current-range/set-block/hanging-selection.js @@ -0,0 +1,33 @@ +/** @jsx h */ + +import h from '../../../helpers/h' + +export default function(change) { + change.setBlock({ type: 'code' }) +} + +export const input = ( + + + + word + + + another + + + +) + +export const output = ( + + + + word + + + another + + + +)