diff --git a/packages/slate-react/src/plugins/before.js b/packages/slate-react/src/plugins/before.js index 6266758f9..d56178936 100644 --- a/packages/slate-react/src/plugins/before.js +++ b/packages/slate-react/src/plugins/before.js @@ -248,15 +248,19 @@ function BeforePlugin() { */ function onDragOver(event, change, editor) { + // If the target is inside a void node, and only in this case, + // call `preventDefault` to signal that drops are allowed. + // When the target is editable, dropping is already allowed by + // default, and calling `preventDefault` hides the cursor. + const node = findNode(event.target, editor.value) + if (node.isVoid) event.preventDefault() + // If a drag is already in progress, don't do this again. if (isDragging) return true isDragging = true event.nativeEvent.dataTransfer.dropEffect = 'move' - // You must call `preventDefault` to signal that drops are allowed. - event.preventDefault() - debug('onDragOver', { event }) } diff --git a/packages/slate-react/src/utils/get-event-range.js b/packages/slate-react/src/utils/get-event-range.js index 676880721..025b48964 100644 --- a/packages/slate-react/src/utils/get-event-range.js +++ b/packages/slate-react/src/utils/get-event-range.js @@ -1,7 +1,8 @@ import getWindow from 'get-window' -import findDOMNode from './find-dom-node' +import { Range } from 'slate' +import findNode from './find-node' import findRange from './find-range' /** @@ -17,46 +18,47 @@ function getEventRange(event, value) { event = event.nativeEvent } - const { x, y } = event + const { x, y, target } = event if (x == null || y == null) return null - // Resolve a range from the caret position where the drop occured. - const window = getWindow(event.target) - let r - - // COMPAT: In Firefox, `caretRangeFromPoint` doesn't exist. (2016/07/25) - if (window.document.caretRangeFromPoint) { - r = window.document.caretRangeFromPoint(x, y) - } else { - const position = window.document.caretPositionFromPoint(x, y) - r = window.document.createRange() - r.setStart(position.offsetNode, position.offset) - r.setEnd(position.offsetNode, position.offset) - } - - // Resolve a Slate range from the DOM range. - let range = findRange(r, value) - if (!range) return null - const { document } = value - const node = document.getNode(range.anchorKey) - const parent = document.getParent(node.key) - const el = findDOMNode(parent) + const node = findNode(target, value) + if (!node) return null // If the drop target is inside a void node, move it into either the next or // previous node, depending on which side the `x` and `y` coordinates are // closest to. - if (parent.isVoid) { - const rect = el.getBoundingClientRect() - const isPrevious = parent.kind == 'inline' + if (node.isVoid) { + const rect = target.getBoundingClientRect() + const isPrevious = node.kind == 'inline' ? x - rect.left < rect.left + rect.width - x : y - rect.top < rect.top + rect.height - y - range = isPrevious - ? range.moveToEndOf(document.getPreviousText(node.key)) - : range.moveToStartOf(document.getNextText(node.key)) + const text = node.getFirstText() + const range = Range.create() + return isPrevious + ? range.moveToEndOf(document.getPreviousText(text.key)) + : range.moveToStartOf(document.getNextText(text.key)) } + // Else resolve a range from the caret position where the drop occured. + const window = getWindow(target) + let native + + // COMPAT: In Firefox, `caretRangeFromPoint` doesn't exist. (2016/07/25) + if (window.document.caretRangeFromPoint) { + native = window.document.caretRangeFromPoint(x, y) + } else { + const position = window.document.caretPositionFromPoint(x, y) + native = window.document.createRange() + native.setStart(position.offsetNode, position.offset) + native.setEnd(position.offsetNode, position.offset) + } + + // Resolve a Slate range from the DOM range. + const range = findRange(native, value) + if (!range) return null + return range }