Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix duplicated content after drag and drop #3562

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions docs/api/locations.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Location

The `Location` interface is a union of the ways to refer to a specific location in a Slate document: paths, points or ranges. Methods will often accept a `Location` instead of requiring only a `Path`, `Point` or `Range`.
The `Location` interface is a union of the ways to refer to a specific location in a Slate document: paths, points or ranges. Methods will often accept a `Location` instead of requiring only a `Path`, `Point` or `Range`.

```typescript
type Location = Path | Point | Range
Expand Down Expand Up @@ -96,7 +96,7 @@ Get the intersection of one `range` with `another`.

###### `Range.isBackward(range: Range): boolean`

Check if a `range` is backward, meaning that its anchor point appears *after* its focus point in the document.
Check if a `range` is backward, meaning that its anchor point appears _after_ its focus point in the document.

###### `Range.isCollapsed(range: Range): boolean`

Expand Down Expand Up @@ -126,5 +126,4 @@ Get the start point of a `range`

Transform a `range` by an `op`.

Options: `{affinity: 'forward' | 'backward' |
'outward' | 'inward' | null}`
Options: `{affinity: 'forward' | 'backward' | 'outward' | 'inward' | null}`
6 changes: 3 additions & 3 deletions docs/api/nodes.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Node

The `Node` union type represents all of the different types of nodes that occur in a Slate document tree.
The `Node` union type represents all of the different types of nodes that occur in a Slate document tree.

```typescript
type Node = Editor | Element | Text
Expand Down Expand Up @@ -57,7 +57,7 @@ Get the first node entry in a root node from a `path`.

###### `Node.fragment(root: Node, range: Range): Descendant[]`

Get the sliced fragment represented by the `range`.
Get the sliced fragment represented by the `range`.

###### `Node.get(root: Node, path: Path): Node`

Expand Down Expand Up @@ -85,7 +85,7 @@ Get the node at a specific `path`, ensuring it's a leaf text node. If the node i

###### `Node.levels(root: Node, path: Path, options?): Iterable<NodeEntry>`

Return an iterable of the nodes in a branch of the tree, from a specific `path`. By default, the order is top-down, from the lowest to the highest node in the tree, but you can pass the `reverse: true` option to go bottom-up.
Return an iterable of the nodes in a branch of the tree, from a specific `path`. By default, the order is top-down, from the lowest to the highest node in the tree, but you can pass the `reverse: true` option to go bottom-up.

Options: `{reverse?: boolean}`

Expand Down
12 changes: 6 additions & 6 deletions docs/api/refs.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@

```typescript
interface PointRef {
current: Point | null
affinity: 'forward' | 'backward' | null
unref(): Point | null
current: Point | null
affinity: 'forward' | 'backward' | null
unref(): Point | null
}
```

Expand All @@ -26,9 +26,9 @@ Transform the point refs current value by an `op`.

```typescript
interface RangeRef {
current: Range | null
affinity: 'forward' | 'backward' | 'outward' | 'inward' | null
unref(): Range | null
current: Range | null
affinity: 'forward' | 'backward' | 'outward' | 'inward' | null
unref(): Range | null
}
```

Expand Down
24 changes: 12 additions & 12 deletions docs/api/transforms.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,28 @@ Transforms that operate on nodes.

###### NodeOptions

All transforms listed below support a parameter `options`. This includes options specific to the transform, and general `NodeOptions` to specify the place in the document that the transform is applied to.
All transforms listed below support a parameter `options`. This includes options specific to the transform, and general `NodeOptions` to specify the place in the document that the transform is applied to.

```typescript
interface NodeOptions {
at?: Location
match?: (node: Node) => boolean
mode?: 'highest' | 'lowest'
voids?: boolean
at?: Location
match?: (node: Node) => boolean
mode?: 'highest' | 'lowest'
voids?: boolean
}
```

###### `Transforms.insertNodes(editor: Editor, nodes: Node | Node[], options?)`

Insert `nodes` at the specified location in the document. If no location is specified, insert at the current selection. If there is no selection, insert at the end of the document.
Insert `nodes` at the specified location in the document. If no location is specified, insert at the current selection. If there is no selection, insert at the end of the document.

Options supported: `NodeOptions & {hanging?: boolean, select?: boolean}`.
Options supported: `NodeOptions & {hanging?: boolean, select?: boolean}`.

###### `Transforms.removeNodes(editor: Editor, options?)`

Remove nodes at the specified location in the document. If no location is specified, remove the nodes in the selection.
Remove nodes at the specified location in the document. If no location is specified, remove the nodes in the selection.

Options supported: `NodeOptions & {hanging?: boolean}`
Options supported: `NodeOptions & {hanging?: boolean}`

###### `Transforms.mergeNodes(editor: Editor, options?)`

Expand All @@ -41,7 +41,7 @@ Options supported: `NodeOptions & {hanging?: boolean}`

Split nodes at the specified location. If no location is specified, split the selection.

Options supported: `NodeOptions & {height?: number, always?: boolean}`
Options supported: `NodeOptions & {height?: number, always?: boolean}`

###### `Transforms.wrapNodes(editor: Editor, element: Element, options?)`

Expand Down Expand Up @@ -75,7 +75,7 @@ Options supported: `NodeOptions`. For `options.mode`, `'all'` is also supported.

###### `Transforms.moveNodes(editor: Editor, options)`

Move the nodes from an origin to a destination. A destination must be specified in the `options`. If no origin is specified, move the selection.
Move the nodes from an origin to a destination. A destination must be specified in the `options`. If no origin is specified, move the selection.

Options supported: `NodeOptions & {to: Path}`. For `options.mode`, `'all'` is also supported.

Expand All @@ -87,7 +87,7 @@ Transforms that operate on the document's selection.

Collapse the selection to a single point.

Options: `{edge?: 'anchor' | 'focus' | 'start' | 'end'}`
Options: `{edge?: 'anchor' | 'focus' | 'start' | 'end'}`

###### `Transforms.select(editor: Editor, target: Location)`

Expand Down
3 changes: 1 addition & 2 deletions docs/walkthroughs/01-installing-slate.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,9 @@ _Note, if you'd rather use a pre-bundled version of Slate, you can `yarn add sla

Once you've installed Slate, you'll need to import it.


```jsx
// Import React dependencies.
import React, { useEffect, useMemo, useState } from "react";
import React, { useEffect, useMemo, useState } from 'react'
// Import the Slate editor factory.
import { createEditor } from 'slate'

Expand Down
2 changes: 1 addition & 1 deletion docs/walkthroughs/02-adding-event-handlers.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ const App = () => {
// Prevent the ampersand character from being inserted.
event.preventDefault()
// Execute the `insertText` method when the event occurs.
editor.insertText("and")
editor.insertText('and')
}
}}
/>
Expand Down
4 changes: 2 additions & 2 deletions docs/walkthroughs/03-defining-custom-elements.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const App = () => {
onKeyDown={event => {
if (event.key === '&') {
event.preventDefault()
editor.insertText("and")
editor.insertText('and')
}
}}
/>
Expand Down Expand Up @@ -93,7 +93,7 @@ const App = () => {
onKeyDown={event => {
if (event.key === '&') {
event.preventDefault()
editor.insertText("and")
editor.insertText('and')
}
}}
/>
Expand Down
34 changes: 17 additions & 17 deletions packages/slate-react/src/components/editable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ export const Editable = (props: EditableProps) => {
isComposing: false,
isUpdatingSelection: false,
latestElement: null as DOMElement | null,
isDraggingInternally: false,
}),
[]
)
Expand Down Expand Up @@ -265,16 +266,16 @@ export const Editable = (props: EditableProps) => {
if (
selection &&
Range.isExpanded(selection) &&
type.startsWith('delete')
type.startsWith('delete') &&
type !== 'deleteByDrag'
) {
Editor.deleteFragment(editor)
return
}

switch (type) {
case 'deleteByComposition':
case 'deleteByCut':
case 'deleteByDrag': {
case 'deleteByCut': {
Editor.deleteFragment(editor)
break
}
Expand Down Expand Up @@ -333,7 +334,6 @@ export const Editable = (props: EditableProps) => {
}

case 'insertFromComposition':
case 'insertFromDrop':
case 'insertFromPaste':
case 'insertFromYank':
case 'insertReplacementText':
Expand Down Expand Up @@ -680,6 +680,8 @@ export const Editable = (props: EditableProps) => {
Transforms.select(editor, range)
}

state.isDraggingInternally = true

ReactEditor.setFragmentData(editor, event.dataTransfer)
}
},
Expand All @@ -692,24 +694,22 @@ export const Editable = (props: EditableProps) => {
!readOnly &&
!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()
const range = ReactEditor.findEventRange(editor, event)
const dragged = editor.selection
const data = event.dataTransfer
Transforms.select(editor, range)
if (state.isDraggingInternally && dragged) {
Transforms.delete(editor, { at: dragged })
}
ReactEditor.insertData(editor, data)
}
},
[readOnly, attributes.onDrop]
)}
onDragEnd={useCallback((event: React.DragEvent<HTMLDivElement>) => {
state.isDraggingInternally = false
}, [])}
onFocus={useCallback(
(event: React.FocusEvent<HTMLDivElement>) => {
if (
Expand Down