mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-04-20 05:11:53 +02:00
Fix overly-aggressive unhangRange (#5193)
`Editor.unhangRange()` could decide to proceed with an adjustment in cases where the range was not hanging. Because the algorithm it uses *always* skips over the first node it encounters, this meant the selection was adjusted in non-hanging cases. This change reduces the chances of an incorrect decision to adjust. Transforms now pass the `voids` flag to `unhangRange()` as it seems logical that the adjusted range should reflect the intention of the operation. This fixes a unit test I added for markable voids that had to be skipped because of the `unhangRange()` error, and fixes a couple other long-skipped tests.
This commit is contained in:
parent
c8c75e9e2d
commit
6909a8f7da
5
.changeset/purple-planes-study.md
Normal file
5
.changeset/purple-planes-study.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
'slate': patch
|
||||
---
|
||||
|
||||
Stops Editor.unhangRange() from adjusting the range in some cases when it was not actually hanging
|
@ -1632,13 +1632,19 @@ export const Editor: EditorInterface = {
|
||||
let [start, end] = Range.edges(range)
|
||||
|
||||
// PERF: exit early if we can guarantee that the range isn't hanging.
|
||||
if (start.offset !== 0 || end.offset !== 0 || Range.isCollapsed(range)) {
|
||||
if (
|
||||
start.offset !== 0 ||
|
||||
end.offset !== 0 ||
|
||||
Range.isCollapsed(range) ||
|
||||
Path.hasPrevious(end.path)
|
||||
) {
|
||||
return range
|
||||
}
|
||||
|
||||
const endBlock = Editor.above(editor, {
|
||||
at: end,
|
||||
match: n => Editor.isBlock(editor, n),
|
||||
voids,
|
||||
})
|
||||
const blockPath = endBlock ? endBlock[1] : []
|
||||
const first = Editor.start(editor, start)
|
||||
|
@ -180,7 +180,7 @@ export const NodeTransforms: NodeTransforms = {
|
||||
|
||||
if (Range.isRange(at)) {
|
||||
if (!hanging) {
|
||||
at = Editor.unhangRange(editor, at)
|
||||
at = Editor.unhangRange(editor, at, { voids })
|
||||
}
|
||||
|
||||
if (Range.isCollapsed(at)) {
|
||||
@ -345,7 +345,7 @@ export const NodeTransforms: NodeTransforms = {
|
||||
}
|
||||
|
||||
if (!hanging && Range.isRange(at)) {
|
||||
at = Editor.unhangRange(editor, at)
|
||||
at = Editor.unhangRange(editor, at, { voids })
|
||||
}
|
||||
|
||||
if (Range.isRange(at)) {
|
||||
@ -543,7 +543,7 @@ export const NodeTransforms: NodeTransforms = {
|
||||
}
|
||||
|
||||
if (!hanging && Range.isRange(at)) {
|
||||
at = Editor.unhangRange(editor, at)
|
||||
at = Editor.unhangRange(editor, at, { voids })
|
||||
}
|
||||
|
||||
const depths = Editor.nodes(editor, { at, match, mode, voids })
|
||||
@ -598,7 +598,7 @@ export const NodeTransforms: NodeTransforms = {
|
||||
}
|
||||
|
||||
if (!hanging && Range.isRange(at)) {
|
||||
at = Editor.unhangRange(editor, at)
|
||||
at = Editor.unhangRange(editor, at, { voids })
|
||||
}
|
||||
|
||||
if (split && Range.isRange(at)) {
|
||||
|
@ -265,7 +265,7 @@ export const TextTransforms: TextTransforms = {
|
||||
return
|
||||
} else if (Range.isRange(at)) {
|
||||
if (!hanging) {
|
||||
at = Editor.unhangRange(editor, at)
|
||||
at = Editor.unhangRange(editor, at, { voids })
|
||||
}
|
||||
|
||||
if (Range.isCollapsed(at)) {
|
||||
|
@ -0,0 +1,29 @@
|
||||
/** @jsx jsx */
|
||||
import { Editor } from 'slate'
|
||||
import { jsx } from '../../..'
|
||||
|
||||
export const input = (
|
||||
<editor>
|
||||
<block>
|
||||
<anchor />
|
||||
This is a first paragraph
|
||||
</block>
|
||||
<block>This is the second paragraph</block>
|
||||
<block void>
|
||||
This is the third paragraph
|
||||
{/* unhang should move focus to here */}
|
||||
</block>
|
||||
<block>
|
||||
<focus />
|
||||
</block>
|
||||
</editor>
|
||||
)
|
||||
|
||||
export const test = editor => {
|
||||
return Editor.unhangRange(editor, editor.selection, { voids: true })
|
||||
}
|
||||
|
||||
export const output = {
|
||||
anchor: { path: [0, 0], offset: 0 },
|
||||
focus: { path: [2, 0], offset: 27 },
|
||||
}
|
@ -8,8 +8,11 @@ export const input = (
|
||||
<anchor />
|
||||
This is a first paragraph
|
||||
</block>
|
||||
<block>This is the second paragraph</block>
|
||||
<block void />
|
||||
<block>
|
||||
This is the second paragraph
|
||||
{/* unhang should move focus to here because, without `voids` set, it should skip over void block below */}
|
||||
</block>
|
||||
<block void>This void paragraph gets skipped over</block>
|
||||
<block>
|
||||
<focus />
|
||||
</block>
|
||||
|
@ -0,0 +1,30 @@
|
||||
/** @jsx jsx */
|
||||
import { Editor } from 'slate'
|
||||
import { jsx } from '../../..'
|
||||
|
||||
export const input = (
|
||||
<editor>
|
||||
<block>
|
||||
<anchor />
|
||||
This is a first paragraph
|
||||
<inline void>
|
||||
<text />
|
||||
</inline>
|
||||
<text />
|
||||
{/* unhang should move focus to here */}
|
||||
</block>
|
||||
<block>
|
||||
<focus />
|
||||
This is the second paragraph
|
||||
</block>
|
||||
</editor>
|
||||
)
|
||||
|
||||
export const test = editor => {
|
||||
return Editor.unhangRange(editor, editor.selection, { voids: true })
|
||||
}
|
||||
|
||||
export const output = {
|
||||
anchor: { path: [0, 0], offset: 0 },
|
||||
focus: { path: [0, 2], offset: 0 },
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/** @jsx jsx */
|
||||
import { Editor } from 'slate'
|
||||
import { jsx } from '../../..'
|
||||
|
||||
export const input = (
|
||||
<editor>
|
||||
<block>
|
||||
<anchor />
|
||||
This is the first paragraph
|
||||
<inline void>
|
||||
<text />
|
||||
</inline>
|
||||
<text />
|
||||
</block>
|
||||
<block>
|
||||
This is the second paragraph
|
||||
<inline void>
|
||||
<text />
|
||||
</inline>
|
||||
<text />
|
||||
{/* unhang should move focus to here */}
|
||||
</block>
|
||||
<block>
|
||||
<focus />
|
||||
This is the third paragraph
|
||||
</block>
|
||||
</editor>
|
||||
)
|
||||
|
||||
export const test = editor => {
|
||||
return Editor.unhangRange(editor, editor.selection, { voids: true })
|
||||
}
|
||||
|
||||
export const output = {
|
||||
anchor: { path: [0, 0], offset: 0 },
|
||||
focus: { path: [1, 2], offset: 0 },
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/** @jsx jsx */
|
||||
/* The starting selection range is not hanging, so should not be adjusted */
|
||||
import { Editor } from 'slate'
|
||||
import { jsx } from '../../..'
|
||||
|
||||
export const input = (
|
||||
<editor>
|
||||
<block>
|
||||
<anchor />
|
||||
This is the first paragraph
|
||||
<inline void>
|
||||
<text />
|
||||
</inline>
|
||||
<text>
|
||||
<focus />
|
||||
</text>
|
||||
</block>
|
||||
<block>This is the second paragraph</block>
|
||||
</editor>
|
||||
)
|
||||
|
||||
export const test = editor => {
|
||||
return Editor.unhangRange(editor, editor.selection, { voids: true })
|
||||
}
|
||||
|
||||
export const output = {
|
||||
anchor: { path: [0, 0], offset: 0 },
|
||||
focus: { path: [0, 2], offset: 0 },
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/** @jsx jsx */
|
||||
/* The starting selection range is not hanging, so should not be adjusted */
|
||||
import { Editor } from 'slate'
|
||||
import { jsx } from '../../..'
|
||||
|
||||
export const input = (
|
||||
<editor>
|
||||
<block>
|
||||
<anchor />
|
||||
This is the first paragraph
|
||||
<inline void>
|
||||
<text />
|
||||
</inline>
|
||||
<text />
|
||||
</block>
|
||||
<block>
|
||||
This is the second paragraph
|
||||
<inline void>
|
||||
<text />
|
||||
</inline>
|
||||
<text>
|
||||
<focus />
|
||||
</text>
|
||||
</block>
|
||||
<block>This is the third paragraph</block>
|
||||
</editor>
|
||||
)
|
||||
|
||||
export const test = editor => {
|
||||
return Editor.unhangRange(editor, editor.selection, { voids: true })
|
||||
}
|
||||
|
||||
export const output = {
|
||||
anchor: { path: [0, 0], offset: 0 },
|
||||
focus: { path: [1, 2], offset: 0 },
|
||||
}
|
@ -28,4 +28,3 @@ export const output = (
|
||||
</block>
|
||||
</editor>
|
||||
)
|
||||
export const skip = true
|
||||
|
@ -25,4 +25,3 @@ export const output = (
|
||||
<block>two</block>
|
||||
</editor>
|
||||
)
|
||||
export const skip = true
|
||||
|
@ -47,5 +47,3 @@ export const output = (
|
||||
</block>
|
||||
</editor>
|
||||
)
|
||||
// TODO this has to be skipped because the second void and the final empty text fail to be marked bold
|
||||
export const skip = true
|
||||
|
Loading…
x
Reference in New Issue
Block a user