1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-04-21 13:51:59 +02:00

Fix duplicated content and other bugs related to drag and drop handling ()

* Fix drag and drop logic

* Add changeset
This commit is contained in:
Claudéric Demers 2021-05-05 19:26:43 -04:00 committed by GitHub
parent f2d110100b
commit c14e1fbc77
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 61 additions and 16 deletions
.changeset
packages/slate-react/src/components

@ -0,0 +1,5 @@
---
'slate-react': patch
---
Fix duplicated content and other bugs related to drag and drop handling

@ -130,6 +130,7 @@ export const Editable = (props: EditableProps) => {
const state = useMemo(
() => ({
isComposing: false,
isDraggingInternally: false,
isUpdatingSelection: false,
latestElement: null as DOMElement | null,
}),
@ -423,7 +424,12 @@ export const Editable = (props: EditableProps) => {
// while a selection is being dragged.
const onDOMSelectionChange = useCallback(
throttle(() => {
if (!readOnly && !state.isComposing && !state.isUpdatingSelection) {
if (
!readOnly &&
!state.isComposing &&
!state.isUpdatingSelection &&
!state.isDraggingInternally
) {
const root = ReactEditor.findDocumentOrShadowRoot(editor)
const { activeElement } = root
const el = ReactEditor.toDOMNode(editor, editor)
@ -748,7 +754,9 @@ export const Editable = (props: EditableProps) => {
) {
const node = ReactEditor.toSlateNode(editor, event.target)
const path = ReactEditor.findPath(editor, node)
const voidMatch = Editor.void(editor, { at: path })
const voidMatch =
Editor.isVoid(editor, node) ||
Editor.void(editor, { at: path, voids: true })
// If starting a drag on a void node, make sure it is selected
// so that it shows up in the selection's fragment.
@ -757,6 +765,8 @@ export const Editable = (props: EditableProps) => {
Transforms.select(editor, range)
}
state.isDraggingInternally = true
ReactEditor.setFragmentData(editor, event.dataTransfer)
}
},
@ -765,28 +775,58 @@ export const Editable = (props: EditableProps) => {
onDrop={useCallback(
(event: React.DragEvent<HTMLDivElement>) => {
if (
hasTarget(editor, event.target) &&
!readOnly &&
hasTarget(editor, event.target) &&
!isEventHandled(event, attributes.onDrop)
) {
// COMPAT: Certain browsers don't fire `beforeinput` events at all, and
// Chromium browsers don't properly fire them for files being
// dropped into a `contenteditable`. (2019/11/26)
// https://bugs.chromium.org/p/chromium/issues/detail?id=1028668
if (
!HAS_BEFORE_INPUT_SUPPORT ||
(!IS_SAFARI && event.dataTransfer.files.length > 0)
) {
event.preventDefault()
const range = ReactEditor.findEventRange(editor, event)
const data = event.dataTransfer
Transforms.select(editor, range)
ReactEditor.insertData(editor, data)
event.preventDefault()
// Keep a reference to the dragged range before updating selection
const draggedRange = editor.selection
// Find the range where the drop happened
const range = ReactEditor.findEventRange(editor, event)
const data = event.dataTransfer
Transforms.select(editor, range)
if (state.isDraggingInternally) {
if (draggedRange) {
Transforms.delete(editor, {
at: draggedRange,
})
}
state.isDraggingInternally = false
}
ReactEditor.insertData(editor, data)
// When dragging from another source into the editor, it's possible
// that the current editor does not have focus.
if (!ReactEditor.isFocused(editor)) {
ReactEditor.focus(editor)
}
}
},
[readOnly, attributes.onDrop]
)}
onDragEnd={useCallback(
(event: React.DragEvent<HTMLDivElement>) => {
// When dropping on a different droppable element than the current editor,
// `onDrop` is not called. So we need to clean up in `onDragEnd` instead.
// Note: `onDragEnd` is only called when `onDrop` is not called
if (
!readOnly &&
state.isDraggingInternally &&
hasTarget(editor, event.target) &&
!isEventHandled(event, attributes.onDragEnd)
) {
state.isDraggingInternally = false
}
},
[readOnly, attributes.onDragEnd]
)}
onFocus={useCallback(
(event: React.FocusEvent<HTMLDivElement>) => {
if (