mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-31 02:49:56 +02:00
Editor.next and Editor.previous now return the first match (#3957)
* Fixes to Editor.next and Editor.previous along with methods used therein (Editor.before, Editor.after, Editor.positions).
This commit is contained in:
@@ -121,6 +121,7 @@ export const Editor = {
|
|||||||
options: {
|
options: {
|
||||||
distance?: number
|
distance?: number
|
||||||
unit?: 'offset' | 'character' | 'word' | 'line' | 'block'
|
unit?: 'offset' | 'character' | 'word' | 'line' | 'block'
|
||||||
|
voids?: boolean
|
||||||
} = {}
|
} = {}
|
||||||
): Point | undefined {
|
): Point | undefined {
|
||||||
const anchor = Editor.point(editor, at, { edge: 'end' })
|
const anchor = Editor.point(editor, at, { edge: 'end' })
|
||||||
@@ -130,7 +131,10 @@ export const Editor = {
|
|||||||
let d = 0
|
let d = 0
|
||||||
let target
|
let target
|
||||||
|
|
||||||
for (const p of Editor.positions(editor, { ...options, at: range })) {
|
for (const p of Editor.positions(editor, {
|
||||||
|
...options,
|
||||||
|
at: range,
|
||||||
|
})) {
|
||||||
if (d > distance) {
|
if (d > distance) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -155,6 +159,7 @@ export const Editor = {
|
|||||||
options: {
|
options: {
|
||||||
distance?: number
|
distance?: number
|
||||||
unit?: 'offset' | 'character' | 'word' | 'line' | 'block'
|
unit?: 'offset' | 'character' | 'word' | 'line' | 'block'
|
||||||
|
voids?: boolean
|
||||||
} = {}
|
} = {}
|
||||||
): Point | undefined {
|
): Point | undefined {
|
||||||
const anchor = Editor.start(editor, [])
|
const anchor = Editor.start(editor, [])
|
||||||
@@ -570,9 +575,13 @@ export const Editor = {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const [, from] = Editor.last(editor, at)
|
const pointAfterLocation = Editor.after(editor, at, { voids })
|
||||||
|
|
||||||
|
if (!pointAfterLocation) return
|
||||||
|
|
||||||
const [, to] = Editor.last(editor, [])
|
const [, to] = Editor.last(editor, [])
|
||||||
const span: Span = [from, to]
|
|
||||||
|
const span: Span = [pointAfterLocation.path, to]
|
||||||
|
|
||||||
if (Path.isPath(at) && at.length === 0) {
|
if (Path.isPath(at) && at.length === 0) {
|
||||||
throw new Error(`Cannot get the next node from the root node!`)
|
throw new Error(`Cannot get the next node from the root node!`)
|
||||||
@@ -587,7 +596,7 @@ export const Editor = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const [, next] = Editor.nodes(editor, { at: span, match, mode, voids })
|
const [next] = Editor.nodes(editor, { at: span, match, mode, voids })
|
||||||
return next
|
return next
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -973,8 +982,9 @@ export const Editor = {
|
|||||||
* can pass the `unit: 'character'` option to moved forward one character, word,
|
* can pass the `unit: 'character'` option to moved forward one character, word,
|
||||||
* or line at at time.
|
* or line at at time.
|
||||||
*
|
*
|
||||||
* Note: void nodes are treated as a single point, and iteration will not
|
* Note: By default void nodes are treated as a single point and iteration
|
||||||
* happen inside their content.
|
* will not happen inside their content unless you pass in true for the
|
||||||
|
* voids option, then iteration will occur.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
*positions(
|
*positions(
|
||||||
@@ -983,9 +993,15 @@ export const Editor = {
|
|||||||
at?: Location
|
at?: Location
|
||||||
unit?: 'offset' | 'character' | 'word' | 'line' | 'block'
|
unit?: 'offset' | 'character' | 'word' | 'line' | 'block'
|
||||||
reverse?: boolean
|
reverse?: boolean
|
||||||
|
voids?: boolean
|
||||||
} = {}
|
} = {}
|
||||||
): Generator<Point, void, undefined> {
|
): Generator<Point, void, undefined> {
|
||||||
const { at = editor.selection, unit = 'offset', reverse = false } = options
|
const {
|
||||||
|
at = editor.selection,
|
||||||
|
unit = 'offset',
|
||||||
|
reverse = false,
|
||||||
|
voids = false,
|
||||||
|
} = options
|
||||||
|
|
||||||
if (!at) {
|
if (!at) {
|
||||||
return
|
return
|
||||||
@@ -1024,11 +1040,12 @@ export const Editor = {
|
|||||||
distance = available >= 0 ? null : 0 - available
|
distance = available >= 0 ? null : 0 - available
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [node, path] of Editor.nodes(editor, { at, reverse })) {
|
for (const [node, path] of Editor.nodes(editor, { at, reverse, voids })) {
|
||||||
if (Element.isElement(node)) {
|
if (Element.isElement(node)) {
|
||||||
// Void nodes are a special case, since we don't want to iterate over
|
// Void nodes are a special case, so by default we will always
|
||||||
// their content. We instead always just yield their first point.
|
// yield their first point. If the voids option is set to true,
|
||||||
if (editor.isVoid(node)) {
|
// then we will iterate over their content
|
||||||
|
if (!voids && editor.isVoid(node)) {
|
||||||
yield Editor.start(editor, path)
|
yield Editor.start(editor, path)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -1045,7 +1062,7 @@ export const Editor = {
|
|||||||
? start
|
? start
|
||||||
: Editor.start(editor, path)
|
: Editor.start(editor, path)
|
||||||
|
|
||||||
const text = Editor.string(editor, { anchor: s, focus: e })
|
const text = Editor.string(editor, { anchor: s, focus: e }, { voids })
|
||||||
string = reverse ? reverseText(text) : text
|
string = reverse ? reverseText(text) : text
|
||||||
isNewBlock = true
|
isNewBlock = true
|
||||||
}
|
}
|
||||||
@@ -1107,9 +1124,17 @@ export const Editor = {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const [, from] = Editor.first(editor, at)
|
const pointBeforeLocation = Editor.before(editor, at, { voids })
|
||||||
|
|
||||||
|
if (!pointBeforeLocation) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const [, to] = Editor.first(editor, [])
|
const [, to] = Editor.first(editor, [])
|
||||||
const span: Span = [from, to]
|
|
||||||
|
// The search location is from the start of the document to the path of
|
||||||
|
// the point before the location passed in
|
||||||
|
const span: Span = [pointBeforeLocation.path, to]
|
||||||
|
|
||||||
if (Path.isPath(at) && at.length === 0) {
|
if (Path.isPath(at) && at.length === 0) {
|
||||||
throw new Error(`Cannot get the previous node from the root node!`)
|
throw new Error(`Cannot get the previous node from the root node!`)
|
||||||
@@ -1124,7 +1149,7 @@ export const Editor = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const [, previous] = Editor.nodes(editor, {
|
const [previous] = Editor.nodes(editor, {
|
||||||
reverse: true,
|
reverse: true,
|
||||||
at: span,
|
at: span,
|
||||||
match,
|
match,
|
||||||
@@ -1217,11 +1242,18 @@ export const Editor = {
|
|||||||
/**
|
/**
|
||||||
* Get the text string content of a location.
|
* Get the text string content of a location.
|
||||||
*
|
*
|
||||||
* Note: the text of void nodes is presumed to be an empty string, regardless
|
* Note: by default the text of void nodes is considered to be an empty
|
||||||
* of what their actual content is.
|
* string, regardless of content, unless you pass in true for the voids option
|
||||||
*/
|
*/
|
||||||
|
|
||||||
string(editor: Editor, at: Location): string {
|
string(
|
||||||
|
editor: Editor,
|
||||||
|
at: Location,
|
||||||
|
options: {
|
||||||
|
voids?: boolean
|
||||||
|
} = {}
|
||||||
|
): string {
|
||||||
|
const { voids = false } = options
|
||||||
const range = Editor.range(editor, at)
|
const range = Editor.range(editor, at)
|
||||||
const [start, end] = Range.edges(range)
|
const [start, end] = Range.edges(range)
|
||||||
let text = ''
|
let text = ''
|
||||||
@@ -1229,6 +1261,7 @@ export const Editor = {
|
|||||||
for (const [node, path] of Editor.nodes(editor, {
|
for (const [node, path] of Editor.nodes(editor, {
|
||||||
at: range,
|
at: range,
|
||||||
match: Text.isText,
|
match: Text.isText,
|
||||||
|
voids,
|
||||||
})) {
|
})) {
|
||||||
let t = node.text
|
let t = node.text
|
||||||
|
|
||||||
|
19
packages/slate/test/interfaces/Editor/after/path-void.tsx
Normal file
19
packages/slate/test/interfaces/Editor/after/path-void.tsx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block void>
|
||||||
|
<text>one</text>
|
||||||
|
<text>two</text>
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const test = editor => {
|
||||||
|
return Editor.after(editor, [0, 0], { voids: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const output = { path: [0, 1], offset: 0 }
|
16
packages/slate/test/interfaces/Editor/after/point-void.tsx
Normal file
16
packages/slate/test/interfaces/Editor/after/point-void.tsx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block void>one</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const test = editor => {
|
||||||
|
return Editor.after(editor, { path: [0, 0], offset: 1 }, { voids: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const output = { path: [0, 0], offset: 2 }
|
24
packages/slate/test/interfaces/Editor/after/range-void.tsx
Normal file
24
packages/slate/test/interfaces/Editor/after/range-void.tsx
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block void>one</block>
|
||||||
|
<block void>two</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const test = editor => {
|
||||||
|
return Editor.after(
|
||||||
|
editor,
|
||||||
|
{
|
||||||
|
anchor: { path: [0, 0], offset: 1 },
|
||||||
|
focus: { path: [1, 0], offset: 2 },
|
||||||
|
},
|
||||||
|
{ voids: true }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const output = { path: [1, 0], offset: 3 }
|
17
packages/slate/test/interfaces/Editor/before/path-void.tsx
Normal file
17
packages/slate/test/interfaces/Editor/before/path-void.tsx
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block void>one</block>
|
||||||
|
<block void>two</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const test = editor => {
|
||||||
|
return Editor.before(editor, [1, 0], { voids: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const output = { path: [0, 0], offset: 3 }
|
16
packages/slate/test/interfaces/Editor/before/point-void.tsx
Normal file
16
packages/slate/test/interfaces/Editor/before/point-void.tsx
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block void>one</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const test = editor => {
|
||||||
|
return Editor.before(editor, { path: [0, 0], offset: 1 }, { voids: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const output = { path: [0, 0], offset: 0 }
|
24
packages/slate/test/interfaces/Editor/before/range-void.tsx
Normal file
24
packages/slate/test/interfaces/Editor/before/range-void.tsx
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block void>one</block>
|
||||||
|
<block void>two</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const test = editor => {
|
||||||
|
return Editor.before(
|
||||||
|
editor,
|
||||||
|
{
|
||||||
|
anchor: { path: [0, 0], offset: 1 },
|
||||||
|
focus: { path: [0, 1], offset: 2 },
|
||||||
|
},
|
||||||
|
{ voids: true }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const output = { path: [0, 0], offset: 0 }
|
@@ -0,0 +1,20 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block void>one</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
export const test = editor => {
|
||||||
|
return Array.from(
|
||||||
|
Editor.positions(editor, { at: [], reverse: true, voids: true })
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export const output = [
|
||||||
|
{ path: [0, 0], offset: 3 },
|
||||||
|
{ path: [0, 0], offset: 2 },
|
||||||
|
{ path: [0, 0], offset: 1 },
|
||||||
|
{ path: [0, 0], offset: 0 },
|
||||||
|
]
|
@@ -0,0 +1,18 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block void>one</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
export const test = editor => {
|
||||||
|
return Array.from(Editor.positions(editor, { at: [], voids: true }))
|
||||||
|
}
|
||||||
|
export const output = [
|
||||||
|
{ path: [0, 0], offset: 0 },
|
||||||
|
{ path: [0, 0], offset: 1 },
|
||||||
|
{ path: [0, 0], offset: 2 },
|
||||||
|
{ path: [0, 0], offset: 3 },
|
||||||
|
]
|
@@ -0,0 +1,32 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block void>
|
||||||
|
one<inline>two</inline>three
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
export const test = editor => {
|
||||||
|
return Array.from(
|
||||||
|
Editor.positions(editor, { at: [], reverse: true, voids: true })
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export const output = [
|
||||||
|
{ path: [0, 2], offset: 5 },
|
||||||
|
{ path: [0, 2], offset: 4 },
|
||||||
|
{ path: [0, 2], offset: 3 },
|
||||||
|
{ path: [0, 2], offset: 2 },
|
||||||
|
{ path: [0, 2], offset: 1 },
|
||||||
|
{ path: [0, 2], offset: 0 },
|
||||||
|
{ path: [0, 1, 0], offset: 3 },
|
||||||
|
{ path: [0, 1, 0], offset: 2 },
|
||||||
|
{ path: [0, 1, 0], offset: 1 },
|
||||||
|
{ path: [0, 1, 0], offset: 0 },
|
||||||
|
{ path: [0, 0], offset: 3 },
|
||||||
|
{ path: [0, 0], offset: 2 },
|
||||||
|
{ path: [0, 0], offset: 1 },
|
||||||
|
{ path: [0, 0], offset: 0 },
|
||||||
|
]
|
@@ -0,0 +1,30 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block void>
|
||||||
|
one<inline>two</inline>three
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
export const test = editor => {
|
||||||
|
return Array.from(Editor.positions(editor, { at: [], voids: true }))
|
||||||
|
}
|
||||||
|
export const output = [
|
||||||
|
{ path: [0, 0], offset: 0 },
|
||||||
|
{ path: [0, 0], offset: 1 },
|
||||||
|
{ path: [0, 0], offset: 2 },
|
||||||
|
{ path: [0, 0], offset: 3 },
|
||||||
|
{ path: [0, 1, 0], offset: 0 },
|
||||||
|
{ path: [0, 1, 0], offset: 1 },
|
||||||
|
{ path: [0, 1, 0], offset: 2 },
|
||||||
|
{ path: [0, 1, 0], offset: 3 },
|
||||||
|
{ path: [0, 2], offset: 0 },
|
||||||
|
{ path: [0, 2], offset: 1 },
|
||||||
|
{ path: [0, 2], offset: 2 },
|
||||||
|
{ path: [0, 2], offset: 3 },
|
||||||
|
{ path: [0, 2], offset: 4 },
|
||||||
|
{ path: [0, 2], offset: 5 },
|
||||||
|
]
|
@@ -0,0 +1,16 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block void>
|
||||||
|
<text>one</text>
|
||||||
|
<text>two</text>
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
export const test = editor => {
|
||||||
|
return Editor.string(editor, [0], { voids: true })
|
||||||
|
}
|
||||||
|
export const output = `onetwo`
|
@@ -4,10 +4,13 @@ import { jsx } from '../../..'
|
|||||||
|
|
||||||
export const input = (
|
export const input = (
|
||||||
<editor>
|
<editor>
|
||||||
<block>one</block>
|
<block>
|
||||||
|
<text>bar</text>
|
||||||
|
<text>foo</text>
|
||||||
|
</block>
|
||||||
<block>
|
<block>
|
||||||
<cursor />
|
<cursor />
|
||||||
two
|
baz
|
||||||
</block>
|
</block>
|
||||||
</editor>
|
</editor>
|
||||||
)
|
)
|
||||||
@@ -17,12 +20,14 @@ export const run = editor => {
|
|||||||
export const output = (
|
export const output = (
|
||||||
<editor>
|
<editor>
|
||||||
<block>
|
<block>
|
||||||
<text />
|
<text>foo</text>
|
||||||
</block>
|
</block>
|
||||||
<block>
|
<block>
|
||||||
one
|
<text>
|
||||||
<cursor />
|
bar
|
||||||
two
|
<cursor />
|
||||||
|
baz
|
||||||
|
</text>
|
||||||
</block>
|
</block>
|
||||||
</editor>
|
</editor>
|
||||||
)
|
)
|
||||||
|
@@ -6,20 +6,22 @@ export const input = (
|
|||||||
<editor>
|
<editor>
|
||||||
<block void>one</block>
|
<block void>one</block>
|
||||||
<block void>two</block>
|
<block void>two</block>
|
||||||
|
<block void>three</block>
|
||||||
</editor>
|
</editor>
|
||||||
)
|
)
|
||||||
export const run = editor => {
|
export const run = editor => {
|
||||||
Transforms.moveNodes(editor, {
|
Transforms.moveNodes(editor, {
|
||||||
at: [0, 0],
|
at: [1, 0],
|
||||||
to: [1, 0],
|
to: [2, 0],
|
||||||
voids: true,
|
voids: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
export const output = (
|
export const output = (
|
||||||
<editor>
|
<editor>
|
||||||
|
<block void>one</block>
|
||||||
<block void>
|
<block void>
|
||||||
<text />
|
<text />
|
||||||
</block>
|
</block>
|
||||||
<block void>onetwo</block>
|
<block void>twothree</block>
|
||||||
</editor>
|
</editor>
|
||||||
)
|
)
|
||||||
|
Reference in New Issue
Block a user