diff --git a/examples/images/index.js b/examples/images/index.js index 6e35c4b1c..2b9850be1 100644 --- a/examples/images/index.js +++ b/examples/images/index.js @@ -1,5 +1,5 @@ -import { Editor } from 'slate-react' +import { Editor, getEventRange, getEventTransfer } from 'slate-react' import { Block, State } from 'slate' import React from 'react' @@ -199,67 +199,36 @@ class Images extends React.Component { * @param {Editor} editor */ - onDrop = (e, data, change, editor) => { - switch (data.type) { - case 'files': return this.onDropOrPasteFiles(e, data, change, editor) - } - } + onDropOrPaste = (e, data, change, editor) => { + const target = getEventRange(e) + if (!target) return - /** - * On drop or paste files, read and insert the image files. - * - * @param {Event} e - * @param {Object} data - * @param {Change} change - * @param {Editor} editor - */ + const transfer = getEventTransfer(e) + const { type, text, files } = transfer - onDropOrPasteFiles = (e, data, change, editor) => { - for (const file of data.files) { - const reader = new FileReader() - const [ type ] = file.type.split('/') - if (type != 'image') continue + if (type == 'files') { + for (const file of files) { + const reader = new FileReader() + const [ mime ] = file.type.split('/') + if (mime != 'image') continue - reader.addEventListener('load', () => { - editor.change((t) => { - t.call(insertImage, reader.result, data.target) + reader.addEventListener('load', () => { + editor.change((c) => { + c.call(insertImage, reader.result, target) + }) }) - }) - reader.readAsDataURL(file) + reader.readAsDataURL(file) + } } - } - /** - * On paste, if the pasted content is an image URL, insert it. - * - * @param {Event} e - * @param {Object} data - * @param {Change} change - * @param {Editor} editor - */ - - onPaste = (e, data, change, editor) => { - switch (data.type) { - case 'files': return this.onDropOrPasteFiles(e, data, change, editor) - case 'text': return this.onPasteText(e, data, change) + if (type == 'text') { + if (!isUrl(text)) return + if (!isImage(text)) return + change.call(insertImage, text, target) } } - /** - * On paste text, if the pasted content is an image URL, insert it. - * - * @param {Event} e - * @param {Object} data - * @param {Change} change - */ - - onPasteText = (e, data, change) => { - if (!isUrl(data.text)) return - if (!isImage(data.text)) return - change.call(insertImage, data.text, data.target) - } - } /** diff --git a/examples/links/index.js b/examples/links/index.js index 03e655f8e..6de53252c 100644 --- a/examples/links/index.js +++ b/examples/links/index.js @@ -1,5 +1,5 @@ -import { Editor } from 'slate-react' +import { Editor, getEventTransfer } from 'slate-react' import { State } from 'slate' import React from 'react' @@ -132,14 +132,17 @@ class Links extends React.Component { onPaste = (e, data, change) => { if (change.state.isCollapsed) return - if (data.type != 'text' && data.type != 'html') return - if (!isUrl(data.text)) return + + const transfer = getEventTransfer(e) + const { type, text } = transfer + if (type != 'text' && type != 'html') return + if (!isUrl(text)) return if (this.hasLinks()) { change.call(unwrapLink) } - change.call(wrapLink, data.text) + change.call(wrapLink, text) return true } diff --git a/examples/paste-html/index.js b/examples/paste-html/index.js index d5fb2fb41..e190593f6 100644 --- a/examples/paste-html/index.js +++ b/examples/paste-html/index.js @@ -1,6 +1,6 @@ import Html from 'slate-html-serializer' -import { Editor } from 'slate-react' +import { Editor, getEventTransfer } from 'slate-react' import { State } from 'slate' import React from 'react' @@ -180,9 +180,9 @@ class PasteHtml extends React.Component { */ onPaste = (e, data, change) => { - if (data.type != 'html') return - if (data.isShift) return - const { document } = serializer.deserialize(data.html) + const transfer = getEventTransfer(e) + if (transfer.type != 'html') return + const { document } = serializer.deserialize(transfer.html) change.insertFragment(document) return true } diff --git a/packages/slate-dev-logger/src/index.js b/packages/slate-dev-logger/src/index.js index 8eb9d36c4..2540f49fb 100644 --- a/packages/slate-dev-logger/src/index.js +++ b/packages/slate-dev-logger/src/index.js @@ -78,7 +78,7 @@ function warn(message, ...args) { */ function deprecate(version, message, ...args) { - log('warn', `Deprecation (v${version}): ${message}`, ...args) + log('warn', `Deprecation (${version}): ${message}`, ...args) } /** diff --git a/packages/slate-react/src/index.js b/packages/slate-react/src/index.js index 381fb4234..8b92fa3cd 100644 --- a/packages/slate-react/src/index.js +++ b/packages/slate-react/src/index.js @@ -1,6 +1,8 @@ import Editor from './components/editor' import Placeholder from './components/placeholder' +import getEventRange from './utils/get-event-range' +import getEventTransfer from './utils/get-event-transfer' import findDOMNode from './utils/find-dom-node' import findDOMRange from './utils/find-dom-range' import findNode from './utils/find-node' @@ -15,6 +17,8 @@ import findRange from './utils/find-range' export { Editor, Placeholder, + getEventRange, + getEventTransfer, findDOMNode, findDOMRange, findNode, @@ -24,6 +28,8 @@ export { export default { Editor, Placeholder, + getEventRange, + getEventTransfer, findDOMNode, findDOMRange, findNode, diff --git a/packages/slate-react/src/plugins/after.js b/packages/slate-react/src/plugins/after.js index aabee402c..e09c09666 100644 --- a/packages/slate-react/src/plugins/after.js +++ b/packages/slate-react/src/plugins/after.js @@ -12,6 +12,9 @@ import Content from '../components/content' import Placeholder from '../components/placeholder' import findDOMNode from '../utils/find-dom-node' import findPoint from '../utils/find-point' +import findRange from '../utils/find-range' +import getEventRange from '../utils/get-event-range' +import getEventTransfer from '../utils/get-event-transfer' import { IS_CHROME, IS_MAC, IS_SAFARI } from '../constants/environment' /** @@ -39,6 +42,8 @@ function AfterPlugin(options = {}) { placeholderStyle, } = options + let isDraggingInternally = null + /** * On before change, enforce the editor's schema. * @@ -143,7 +148,7 @@ function AfterPlugin(options = {}) { // Create a fake selection so that we can add a Base64-encoded copy of the // fragment to the HTML, to decode on future pastes. - const { fragment } = data + const { fragment } = state const encoded = Base64.serializeNode(fragment) const range = native.getRangeAt(0) let contents = range.cloneContents() @@ -233,6 +238,51 @@ function AfterPlugin(options = {}) { }) } + /** + * On drag end. + * + * @param {Event} event + * @param {Object} data + * @param {Change} change + * @param {Editor} editor + */ + + function onDragEnd(event, data, change, editor) { + debug('onDragEnd', { event }) + + isDraggingInternally = null + } + + /** + * On drag over. + * + * @param {Event} event + * @param {Object} data + * @param {Change} change + * @param {Editor} editor + */ + + function onDragOver(event, data, change, editor) { + debug('onDragOver', { event }) + + isDraggingInternally = false + } + + /** + * On drag start. + * + * @param {Event} event + * @param {Object} data + * @param {Change} change + * @param {Editor} editor + */ + + function onDragStart(event, data, change, editor) { + debug('onDragStart', { event }) + + isDraggingInternally = true + } + /** * On drop. * @@ -241,39 +291,23 @@ function AfterPlugin(options = {}) { * @param {Change} change */ - function onDrop(event, data, change) { - debug('onDrop', { data }) - - switch (data.type) { - case 'text': - case 'html': - return onDropText(event, data, change) - case 'fragment': - return onDropFragment(event, data, change) - case 'node': - return onDropNode(event, data, change) - } - } - - /** - * On drop node. - * - * @param {Event} event - * @param {Object} data - * @param {Change} change - */ - - function onDropNode(event, data, change) { - debug('onDropNode', { data }) + function onDrop(event, data, change, editor) { + debug('onDrop', { event }) const { state } = change const { selection } = state - let { node, target, isInternal } = data + let target = getEventRange(event, state) + if (!target) return + + const transfer = getEventTransfer(event) + const { type, fragment, node, text } = transfer + + change.focus() // If the drag is internal and the target is after the selection, it // needs to account for the selection's content being deleted. if ( - isInternal && + isDraggingInternally && selection.endKey == target.endKey && selection.endOffset < target.endOffset ) { @@ -282,103 +316,47 @@ function AfterPlugin(options = {}) { : 0 - selection.endOffset) } - if (isInternal) { + if (isDraggingInternally) { change.delete() } - if (Block.isBlock(node)) { - change - .select(target) - .focus() - .insertBlock(node) - .removeNodeByKey(node.key) - } + change.select(target) - if (Inline.isInline(node)) { - change - .select(target) - .focus() - .insertInline(node) - .removeNodeByKey(node.key) - } - } + if (type == 'text' || type == 'html') { + const { anchorKey } = target + let hasVoidParent = document.hasVoidParent(anchorKey) - /** - * On drop fragment. - * - * @param {Event} event - * @param {Object} data - * @param {Change} change - */ + if (hasVoidParent) { + let n = document.getNode(anchorKey) - function onDropFragment(event, data, change) { - debug('onDropFragment', { data }) + while (hasVoidParent) { + n = document.getNextText(n.key) + if (!n) break + hasVoidParent = document.hasVoidParent(n.key) + } - const { state } = change - const { selection } = state - let { fragment, target, isInternal } = data - - // If the drag is internal and the target is after the selection, it - // needs to account for the selection's content being deleted. - if ( - isInternal && - selection.endKey == target.endKey && - selection.endOffset < target.endOffset - ) { - target = target.move(selection.startKey == selection.endKey - ? 0 - selection.endOffset + selection.startOffset - : 0 - selection.endOffset) - } - - if (isInternal) { - change.delete() - } - - change - .select(target) - .focus() - .insertFragment(fragment) - } - - /** - * On drop text. - * - * @param {Event} event - * @param {Object} data - * @param {Change} change - */ - - function onDropText(event, data, change) { - debug('onDropText', { data }) - - const { state } = change - const { document } = state - const { text, target } = data - const { anchorKey } = target - - change.select(target).focus() - - let hasVoidParent = document.hasVoidParent(anchorKey) - - // Insert text into nearest text node - if (hasVoidParent) { - let node = document.getNode(anchorKey) - - while (hasVoidParent) { - node = document.getNextText(node.key) - if (!node) break - hasVoidParent = document.hasVoidParent(node.key) + if (n) change.collapseToStartOf(n) } - if (node) change.collapseToStartOf(node) + text + .split('\n') + .forEach((line, i) => { + if (i > 0) change.splitBlock() + change.insertText(line) + }) } - text - .split('\n') - .forEach((line, i) => { - if (i > 0) change.splitBlock() - change.insertText(line) - }) + if (type == 'fragment') { + change.insertFragment(fragment) + } + + if (type == 'node' && Block.isBlock(node)) { + change.insertBlock(node).removeNodeByKey(node.key) + } + + if (type == 'node' && Inline.isInline(node)) { + change.insertInline(node).removeNodeByKey(node.key) + } } /** @@ -733,48 +711,23 @@ function AfterPlugin(options = {}) { function onPaste(event, data, change) { debug('onPaste', { data }) - switch (data.type) { - case 'fragment': - return onPasteFragment(event, data, change) - case 'text': - case 'html': - return onPasteText(event, data, change) + const transfer = getEventTransfer(event) + const { type, fragment, text } = transfer + + if (type == 'fragment') { + change.insertFragment(fragment) } - } - /** - * On paste fragment. - * - * @param {Event} event - * @param {Object} data - * @param {Change} change - */ + if (type == 'text' || type == 'html') { + const { state } = change + const { document, selection, startBlock } = state + if (startBlock.isVoid) return - function onPasteFragment(event, data, change) { - debug('onPasteFragment', { data }) - change.insertFragment(data.fragment) - } - - /** - * On paste text, split blocks at new lines. - * - * @param {Event} event - * @param {Object} data - * @param {Change} change - */ - - function onPasteText(event, data, change) { - debug('onPasteText', { data }) - - const { state } = change - const { document, selection, startBlock } = state - if (startBlock.isVoid) return - - const { text } = data - const defaultBlock = startBlock - const defaultMarks = document.getMarksAtRange(selection.collapseToStart()) - const fragment = Plain.deserialize(text, { defaultBlock, defaultMarks }).document - change.insertFragment(fragment) + const defaultBlock = startBlock + const defaultMarks = document.getMarksAtRange(selection.collapseToStart()) + const frag = Plain.deserialize(text, { defaultBlock, defaultMarks }).document + change.insertFragment(frag) + } } /** @@ -787,7 +740,73 @@ function AfterPlugin(options = {}) { function onSelect(event, data, change) { debug('onSelect', { data }) - change.select(data.selection) + + const window = getWindow(event.target) + const { state } = change + const { document } = state + const native = window.getSelection() + + // If there are no ranges, the editor was blurred natively. + if (!native.rangeCount) { + change.blur() + return + } + + // Otherwise, determine the Slate selection from the native one. + let range = findRange(native, state) + if (!range) return + + const { anchorKey, anchorOffset, focusKey, focusOffset } = range + const anchorText = document.getNode(anchorKey) + const focusText = document.getNode(focusKey) + const anchorInline = document.getClosestInline(anchorKey) + const focusInline = document.getClosestInline(focusKey) + const focusBlock = document.getClosestBlock(focusKey) + const anchorBlock = document.getClosestBlock(anchorKey) + + // COMPAT: If the anchor point is at the start of a non-void, and the + // focus point is inside a void node with an offset that isn't `0`, set + // the focus offset to `0`. This is due to void nodes 's being + // positioned off screen, resulting in the offset always being greater + // than `0`. Since we can't know what it really should be, and since an + // offset of `0` is less destructive because it creates a hanging + // selection, go with `0`. (2017/09/07) + if ( + anchorBlock && + !anchorBlock.isVoid && + anchorOffset == 0 && + focusBlock && + focusBlock.isVoid && + focusOffset != 0 + ) { + range = range.set('focusOffset', 0) + } + + // COMPAT: If the selection is at the end of a non-void inline node, and + // there is a node after it, put it in the node after instead. This + // standardizes the behavior, since it's indistinguishable to the user. + if ( + anchorInline && + !anchorInline.isVoid && + anchorOffset == anchorText.text.length + ) { + const block = document.getClosestBlock(anchorKey) + const next = block.getNextText(anchorKey) + if (next) range = range.moveAnchorTo(next.key, 0) + } + + if ( + focusInline && + !focusInline.isVoid && + focusOffset == focusText.text.length + ) { + const block = document.getClosestBlock(focusKey) + const next = block.getNextText(focusKey) + if (next) range = range.moveFocusTo(next.key, 0) + } + + range = range.normalize(document) + change.select(range) } /** @@ -899,6 +918,9 @@ function AfterPlugin(options = {}) { onBlur, onCopy, onCut, + onDragEnd, + onDragOver, + onDragStart, onDrop, onInput, onKeyDown, diff --git a/packages/slate-react/src/plugins/before.js b/packages/slate-react/src/plugins/before.js index 190a02fc7..7fd886a90 100644 --- a/packages/slate-react/src/plugins/before.js +++ b/packages/slate-react/src/plugins/before.js @@ -9,7 +9,8 @@ import { findDOMNode } from 'react-dom' import HOTKEYS from '../constants/hotkeys' import TRANSFER_TYPES from '../constants/transfer-types' import findRange from '../utils/find-range' -import getTransferData from '../utils/get-transfer-data' +import getEventRange from '../utils/get-event-range' +import getEventTransfer from '../utils/get-event-transfer' import setTransferData from '../utils/set-transfer-data' import { IS_FIREFOX, IS_MAC, SUPPORTED_EVENTS } from '../constants/environment' @@ -135,8 +136,8 @@ function BeforePlugin() { window.requestAnimationFrame(() => isCopying = false) const { state } = change - data.type = 'fragment' - data.fragment = state.fragment + defineDeprecatedData(data, 'type', 'fragment') + defineDeprecatedData(data, 'fragment', state.fragment) debug('onCopy', { event }) } @@ -158,8 +159,8 @@ function BeforePlugin() { window.requestAnimationFrame(() => isCopying = false) const { state } = change - data.type = 'fragment' - data.fragment = state.fragment + defineDeprecatedData(data, 'type', 'fragment') + defineDeprecatedData(data, 'fragment', state.fragment) debug('onCut', { event }) } @@ -212,12 +213,16 @@ function BeforePlugin() { isDragging = true isInternalDrag = true - const { dataTransfer } = event.nativeEvent - const d = getTransferData(dataTransfer) - Object.assign(data, d) + const d = getEventTransfer(event) + const { nativeEvent } = event + const { dataTransfer } = nativeEvent - if (data.type != 'node') { - const { state } = this.props + Object.keys(d).forEach((key) => { + defineDeprecatedData(data, key, d[key]) + }) + + if (d.type != 'node') { + const { state } = change const { fragment } = state const encoded = Base64.serializeNode(fragment) setTransferData(dataTransfer, TRANSFER_TYPES.FRAGMENT, encoded) @@ -243,60 +248,29 @@ function BeforePlugin() { const { state } = change const { nativeEvent } = event - const { dataTransfer, x, y } = nativeEvent - const d = getTransferData(dataTransfer) - Object.assign(data, d) + const { dataTransfer } = nativeEvent + const d = getEventTransfer(event) - // Resolve a range from the caret position where the drop occured. - const window = getWindow(event.target) - let range + Object.keys(d).forEach((key) => { + defineDeprecatedData(data, key, d[key]) + }) - // COMPAT: In Firefox, `caretRangeFromPoint` doesn't exist. (2016/07/25) - if (window.document.caretRangeFromPoint) { - range = window.document.caretRangeFromPoint(x, y) - } else { - const position = window.document.caretPositionFromPoint(x, y) - range = window.document.createRange() - range.setStart(position.offsetNode, position.offset) - range.setEnd(position.offsetNode, position.offset) - } - - // Resolve a Slate range from the DOM range. - let selection = findRange(range, state) - if (!selection) return true - - const { document } = state - const node = document.getNode(selection.anchorKey) - const parent = document.getParent(node.key) - const el = findDOMNode(parent) - - // 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' - ? x - rect.left < rect.left + rect.width - x - : y - rect.top < rect.top + rect.height - y - - selection = isPrevious - ? selection.moveToEndOf(document.getPreviousText(node.key)) - : selection.moveToStartOf(document.getNextText(node.key)) - } + const range = getEventRange(event, state) + if (!range) return true // Add drop-specific information to the data. - data.target = selection + defineDeprecatedData(data, 'target', range) // COMPAT: Edge throws "Permission denied" errors when // accessing `dropEffect` or `effectAllowed` (2017/7/12) try { - data.effect = dataTransfer.dropEffect + defineDeprecatedData(data, 'effect', dataTransfer.dropEffect) } catch (err) { - data.effect = null + defineDeprecatedData(data, 'effect', null) } if (d.type == 'fragment' || d.type == 'node') { - data.isInternal = isInternalDrag + defineDeprecatedData(data, 'isInternal', isInternalDrag) } debug('onDrop', { event }) @@ -421,19 +395,14 @@ function BeforePlugin() { if (editor.props.readOnly) return event.preventDefault() - const d = getTransferData(event.clipboardData) - Object.assign(data, d) + const d = getEventTransfer(event) - // COMPAT: Attach the `isShift` flag, so that people can use it to trigger - // "Paste and Match Style" logic. - Object.defineProperty(data, 'isShift', { - enumerable: true, - get() { - logger.deprecate('0.28.0', 'The `data.isShift` property of paste events has been deprecated. If you need this functionality, you\'ll need to keep track of that state with `onKeyDown` and `onKeyUp` events instead') - return isShifting - } + Object.keys(d).forEach((key) => { + defineDeprecatedData(data, key, d[key]) }) + defineDeprecatedData(data, 'isShift', isShifting) + debug('onPaste', { event }) } @@ -458,7 +427,7 @@ function BeforePlugin() { // If there are no ranges, the editor was blurred natively. if (!native.rangeCount) { - data.selection = selection.blur() + defineDeprecatedData(data, 'selection', selection.blur()) } // Otherwise, determine the Slate selection from the native one. @@ -516,7 +485,7 @@ function BeforePlugin() { } range = range.normalize(document) - data.selection = range + defineDeprecatedData(data, 'selection', range) } debug('onSelect', { event }) @@ -549,37 +518,33 @@ function BeforePlugin() { } /** - * Add deprecated `data` fields from a key `event`. - * - * @param {Object} data - * @param {Object} event + * Deprecated. */ +function defineDeprecatedData(data, key, value) { + Object.defineProperty(data, key, { + enumerable: true, + get() { + logger.deprecate('slate-react@0.5.0', `Accessing the \`data.${key}\` property is deprecated, please use the native \`event\` properties instead, or one of the newly exposed helper utilities.`) + return value + } + }) +} + function addDeprecatedKeyProperties(data, event) { const { altKey, ctrlKey, metaKey, shiftKey, which } = event const name = keycode(which) - - function define(key, value) { - Object.defineProperty(data, key, { - enumerable: true, - get() { - logger.deprecate('0.28.0', `The \`data.${key}\` property of keyboard events is deprecated, please use the native \`event\` properties instead.`) - return value - } - }) - } - - define('code', which) - define('key', name) - define('isAlt', altKey) - define('isCmd', IS_MAC ? metaKey && !altKey : false) - define('isCtrl', ctrlKey && !altKey) - define('isLine', IS_MAC ? metaKey : false) - define('isMeta', metaKey) - define('isMod', IS_MAC ? metaKey && !altKey : ctrlKey && !altKey) - define('isModAlt', IS_MAC ? metaKey && altKey : ctrlKey && altKey) - define('isShift', shiftKey) - define('isWord', IS_MAC ? altKey : ctrlKey) + defineDeprecatedData(data, 'code', which) + defineDeprecatedData(data, 'key', name) + defineDeprecatedData(data, 'isAlt', altKey) + defineDeprecatedData(data, 'isCmd', IS_MAC ? metaKey && !altKey : false) + defineDeprecatedData(data, 'isCtrl', ctrlKey && !altKey) + defineDeprecatedData(data, 'isLine', IS_MAC ? metaKey : false) + defineDeprecatedData(data, 'isMeta', metaKey) + defineDeprecatedData(data, 'isMod', IS_MAC ? metaKey && !altKey : ctrlKey && !altKey) + defineDeprecatedData(data, 'isModAlt', IS_MAC ? metaKey && altKey : ctrlKey && altKey) + defineDeprecatedData(data, 'isShift', shiftKey) + defineDeprecatedData(data, 'isWord', IS_MAC ? altKey : ctrlKey) } /** diff --git a/packages/slate-react/src/utils/get-event-range.js b/packages/slate-react/src/utils/get-event-range.js new file mode 100644 index 000000000..0c74953d6 --- /dev/null +++ b/packages/slate-react/src/utils/get-event-range.js @@ -0,0 +1,69 @@ + +import getWindow from 'get-window' + +import findDOMNode from './find-dom-node' +import findRange from './find-range' + +/** + * Get the target range from a DOM `event`. + * + * @param {Event} event + * @param {State} state + * @return {Range} + */ + +function getEventRange(event, state) { + if (event.nativeEvent) { + event = event.nativeEvent + } + + const { x, y } = 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, state) + if (!range) return null + + const { document } = state + const node = document.getNode(range.anchorKey) + const parent = document.getParent(node.key) + const el = findDOMNode(parent) + + // 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' + ? 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)) + } + + return range +} + +/** + * Export. + * + * @type {Function} + */ + +export default getEventRange diff --git a/packages/slate-react/src/utils/get-transfer-data.js b/packages/slate-react/src/utils/get-event-transfer.js similarity index 94% rename from packages/slate-react/src/utils/get-transfer-data.js rename to packages/slate-react/src/utils/get-event-transfer.js index e4b44bb15..a3eed8a1f 100644 --- a/packages/slate-react/src/utils/get-transfer-data.js +++ b/packages/slate-react/src/utils/get-event-transfer.js @@ -12,13 +12,18 @@ import TRANSFER_TYPES from '../constants/transfer-types' const FRAGMENT_MATCHER = / data-slate-fragment="([^\s"]+)"/ /** - * Get the data and type from a native data `transfer`. + * Get the transfer data from an `event`. * - * @param {DataTransfer} transfer + * @param {Event} event * @return {Object} */ -function getTransferData(transfer) { +function getEventTransfer(event) { + if (event.nativeEvent) { + event = event.nativeEvent + } + + const transfer = event.dataTransfer || event.clipboardData let fragment = getType(transfer, TRANSFER_TYPES.FRAGMENT) let node = getType(transfer, TRANSFER_TYPES.NODE) const html = getType(transfer, 'text/html') @@ -148,4 +153,4 @@ function getType(transfer, type) { * @type {Function} */ -export default getTransferData +export default getEventTransfer