mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-30 18:39:51 +02:00
add voids: true
option to transforms and queries (#3265)
This commit is contained in:
@@ -145,7 +145,7 @@ export const createEditor = (): Editor => {
|
|||||||
// Ensure that block and inline nodes have at least one text child.
|
// Ensure that block and inline nodes have at least one text child.
|
||||||
if (Element.isElement(node) && node.children.length === 0) {
|
if (Element.isElement(node) && node.children.length === 0) {
|
||||||
const child = { text: '' }
|
const child = { text: '' }
|
||||||
Editor.insertNodes(editor, child, { at: path.concat(0) })
|
Editor.insertNodes(editor, child, { at: path.concat(0), voids: true })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,43 +175,42 @@ export const createEditor = (): Editor => {
|
|||||||
// other inline nodes, or parent blocks that only contain inlines and
|
// other inline nodes, or parent blocks that only contain inlines and
|
||||||
// text.
|
// text.
|
||||||
if (isInlineOrText !== shouldHaveInlines) {
|
if (isInlineOrText !== shouldHaveInlines) {
|
||||||
Editor.removeNodes(editor, { at: path.concat(n) })
|
Editor.removeNodes(editor, { at: path.concat(n), voids: true })
|
||||||
n--
|
n--
|
||||||
continue
|
} else if (Element.isElement(child)) {
|
||||||
}
|
|
||||||
|
|
||||||
if (Element.isElement(child)) {
|
|
||||||
// Ensure that inline nodes are surrounded by text nodes.
|
// Ensure that inline nodes are surrounded by text nodes.
|
||||||
if (editor.isInline(child)) {
|
if (editor.isInline(child)) {
|
||||||
if (prev == null || !Text.isText(prev)) {
|
if (prev == null || !Text.isText(prev)) {
|
||||||
const newChild = { text: '' }
|
const newChild = { text: '' }
|
||||||
Editor.insertNodes(editor, newChild, { at: path.concat(n) })
|
Editor.insertNodes(editor, newChild, {
|
||||||
|
at: path.concat(n),
|
||||||
|
voids: true,
|
||||||
|
})
|
||||||
n++
|
n++
|
||||||
continue
|
} else if (isLast) {
|
||||||
}
|
|
||||||
|
|
||||||
if (isLast) {
|
|
||||||
const newChild = { text: '' }
|
const newChild = { text: '' }
|
||||||
Editor.insertNodes(editor, newChild, { at: path.concat(n + 1) })
|
Editor.insertNodes(editor, newChild, {
|
||||||
|
at: path.concat(n + 1),
|
||||||
|
voids: true,
|
||||||
|
})
|
||||||
n++
|
n++
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Merge adjacent text nodes that are empty or match.
|
// Merge adjacent text nodes that are empty or match.
|
||||||
if (prev != null && Text.isText(prev)) {
|
if (prev != null && Text.isText(prev)) {
|
||||||
if (Text.equals(child, prev, { loose: true })) {
|
if (Text.equals(child, prev, { loose: true })) {
|
||||||
Editor.mergeNodes(editor, { at: path.concat(n) })
|
Editor.mergeNodes(editor, { at: path.concat(n), voids: true })
|
||||||
n--
|
n--
|
||||||
continue
|
|
||||||
} else if (prev.text === '') {
|
} else if (prev.text === '') {
|
||||||
Editor.removeNodes(editor, { at: path.concat(n - 1) })
|
Editor.removeNodes(editor, {
|
||||||
|
at: path.concat(n - 1),
|
||||||
|
voids: true,
|
||||||
|
})
|
||||||
n--
|
n--
|
||||||
continue
|
|
||||||
} else if (isLast && child.text === '') {
|
} else if (isLast && child.text === '') {
|
||||||
Editor.removeNodes(editor, { at: path.concat(n) })
|
Editor.removeNodes(editor, { at: path.concat(n), voids: true })
|
||||||
n--
|
n--
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -137,9 +137,10 @@ export const LocationQueries = {
|
|||||||
match?: NodeMatch
|
match?: NodeMatch
|
||||||
mode?: 'all' | 'highest'
|
mode?: 'all' | 'highest'
|
||||||
reverse?: boolean
|
reverse?: boolean
|
||||||
|
voids?: boolean
|
||||||
} = {}
|
} = {}
|
||||||
): Iterable<ElementEntry> {
|
): Iterable<ElementEntry> {
|
||||||
for (const [node, path] of this.nodes(editor, options)) {
|
for (const [node, path] of Editor.nodes(editor, options)) {
|
||||||
if (Element.isElement(node)) {
|
if (Element.isElement(node)) {
|
||||||
yield [node, path]
|
yield [node, path]
|
||||||
}
|
}
|
||||||
@@ -239,9 +240,10 @@ export const LocationQueries = {
|
|||||||
options: {
|
options: {
|
||||||
at?: Location
|
at?: Location
|
||||||
reverse?: boolean
|
reverse?: boolean
|
||||||
|
voids?: boolean
|
||||||
} = {}
|
} = {}
|
||||||
): Iterable<NodeEntry> {
|
): Iterable<NodeEntry> {
|
||||||
const { at = editor.selection, reverse = false } = options
|
const { at = editor.selection, reverse = false, voids = false } = options
|
||||||
|
|
||||||
if (!at) {
|
if (!at) {
|
||||||
return
|
return
|
||||||
@@ -253,7 +255,7 @@ export const LocationQueries = {
|
|||||||
for (const [n, p] of Node.levels(editor, path)) {
|
for (const [n, p] of Node.levels(editor, path)) {
|
||||||
levels.push([n, p])
|
levels.push([n, p])
|
||||||
|
|
||||||
if (Element.isElement(n) && editor.isVoid(n)) {
|
if (!voids && Element.isElement(n) && editor.isVoid(n)) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -269,10 +271,18 @@ export const LocationQueries = {
|
|||||||
* Get the first matching node in a single branch of the document.
|
* Get the first matching node in a single branch of the document.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
match(editor: Editor, at: Location, match: NodeMatch): NodeEntry | undefined {
|
match(
|
||||||
|
editor: Editor,
|
||||||
|
at: Location,
|
||||||
|
match: NodeMatch,
|
||||||
|
options: {
|
||||||
|
voids?: boolean
|
||||||
|
} = {}
|
||||||
|
): NodeEntry | undefined {
|
||||||
|
const { voids = false } = options
|
||||||
const path = Editor.path(editor, at)
|
const path = Editor.path(editor, at)
|
||||||
|
|
||||||
for (const entry of Editor.levels(editor, { at: path })) {
|
for (const entry of Editor.levels(editor, { at: path, voids })) {
|
||||||
if (Editor.isMatch(editor, entry, match)) {
|
if (Editor.isMatch(editor, entry, match)) {
|
||||||
return entry
|
return entry
|
||||||
}
|
}
|
||||||
@@ -330,23 +340,21 @@ export const LocationQueries = {
|
|||||||
* Get the matching node in the branch of the document after a location.
|
* Get the matching node in the branch of the document after a location.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
next(editor: Editor, at: Location, match: NodeMatch): NodeEntry | undefined {
|
next(
|
||||||
|
editor: Editor,
|
||||||
|
at: Location,
|
||||||
|
match: NodeMatch,
|
||||||
|
options: {
|
||||||
|
mode?: 'all' | 'highest'
|
||||||
|
voids?: boolean
|
||||||
|
} = {}
|
||||||
|
): NodeEntry | undefined {
|
||||||
|
const { mode = 'highest', voids = false } = options
|
||||||
const [, from] = Editor.last(editor, at)
|
const [, from] = Editor.last(editor, at)
|
||||||
const [, to] = Editor.last(editor, [])
|
const [, to] = Editor.last(editor, [])
|
||||||
const span: Span = [from, to]
|
const span: Span = [from, to]
|
||||||
let i = 0
|
const [, next] = Editor.nodes(editor, { at: span, match, mode, voids })
|
||||||
|
return next
|
||||||
for (const entry of Editor.nodes(editor, {
|
|
||||||
at: span,
|
|
||||||
match,
|
|
||||||
mode: 'highest',
|
|
||||||
})) {
|
|
||||||
if (i === 1) {
|
|
||||||
return entry
|
|
||||||
}
|
|
||||||
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -377,6 +385,7 @@ export const LocationQueries = {
|
|||||||
match?: NodeMatch
|
match?: NodeMatch
|
||||||
mode?: 'all' | 'highest'
|
mode?: 'all' | 'highest'
|
||||||
reverse?: boolean
|
reverse?: boolean
|
||||||
|
voids?: boolean
|
||||||
} = {}
|
} = {}
|
||||||
): Iterable<NodeEntry> {
|
): Iterable<NodeEntry> {
|
||||||
const {
|
const {
|
||||||
@@ -384,6 +393,7 @@ export const LocationQueries = {
|
|||||||
match,
|
match,
|
||||||
mode = 'all',
|
mode = 'all',
|
||||||
reverse = false,
|
reverse = false,
|
||||||
|
voids = false,
|
||||||
} = options
|
} = options
|
||||||
|
|
||||||
if (!at) {
|
if (!at) {
|
||||||
@@ -407,20 +417,19 @@ export const LocationQueries = {
|
|||||||
reverse,
|
reverse,
|
||||||
from,
|
from,
|
||||||
to,
|
to,
|
||||||
pass: ([n]) => Element.isElement(n) && editor.isVoid(n),
|
pass: ([n]) => (voids ? false : Element.isElement(n) && editor.isVoid(n)),
|
||||||
})
|
})
|
||||||
|
|
||||||
let prev: NodeEntry | undefined
|
let prev: NodeEntry | undefined
|
||||||
|
|
||||||
for (const entry of iterable) {
|
for (const entry of iterable) {
|
||||||
if (match != null) {
|
if (match) {
|
||||||
if (mode === 'highest' && prev) {
|
if (
|
||||||
const [, prevPath] = prev
|
mode === 'highest' &&
|
||||||
const [, path] = entry
|
prev &&
|
||||||
|
Path.compare(entry[1], prev[1]) === 0
|
||||||
if (Path.compare(path, prevPath) === 0) {
|
) {
|
||||||
continue
|
continue
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Editor.isMatch(editor, entry, match)) {
|
if (!Editor.isMatch(editor, entry, match)) {
|
||||||
@@ -669,25 +678,25 @@ export const LocationQueries = {
|
|||||||
previous(
|
previous(
|
||||||
editor: Editor,
|
editor: Editor,
|
||||||
at: Location,
|
at: Location,
|
||||||
match: NodeMatch
|
match: NodeMatch,
|
||||||
|
options: {
|
||||||
|
mode?: 'all' | 'highest'
|
||||||
|
voids?: boolean
|
||||||
|
} = {}
|
||||||
): NodeEntry | undefined {
|
): NodeEntry | undefined {
|
||||||
|
const { mode = 'highest', voids = false } = options
|
||||||
const [, from] = Editor.first(editor, at)
|
const [, from] = Editor.first(editor, at)
|
||||||
const [, to] = Editor.first(editor, [])
|
const [, to] = Editor.first(editor, [])
|
||||||
const span: Span = [from, to]
|
const span: Span = [from, to]
|
||||||
let i = 0
|
const [, previous] = Editor.nodes(editor, {
|
||||||
|
|
||||||
for (const entry of Editor.nodes(editor, {
|
|
||||||
match,
|
|
||||||
at: span,
|
|
||||||
reverse: true,
|
reverse: true,
|
||||||
mode: 'highest',
|
at: span,
|
||||||
})) {
|
match,
|
||||||
if (i === 1) {
|
mode,
|
||||||
return entry
|
voids,
|
||||||
}
|
})
|
||||||
|
|
||||||
i++
|
return previous
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -752,9 +761,10 @@ export const LocationQueries = {
|
|||||||
match?: NodeMatch
|
match?: NodeMatch
|
||||||
mode?: 'all' | 'highest'
|
mode?: 'all' | 'highest'
|
||||||
reverse?: boolean
|
reverse?: boolean
|
||||||
|
voids?: boolean
|
||||||
} = {}
|
} = {}
|
||||||
): Iterable<TextEntry> {
|
): Iterable<TextEntry> {
|
||||||
for (const [node, path] of this.nodes(editor, options)) {
|
for (const [node, path] of Editor.nodes(editor, options)) {
|
||||||
if (Text.isText(node)) {
|
if (Text.isText(node)) {
|
||||||
yield [node, path]
|
yield [node, path]
|
||||||
}
|
}
|
||||||
|
@@ -5,7 +5,14 @@ export const RangeQueries = {
|
|||||||
* Convert a range into a non-hanging one.
|
* Convert a range into a non-hanging one.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
unhangRange(editor: Editor, range: Range): Range {
|
unhangRange(
|
||||||
|
editor: Editor,
|
||||||
|
range: Range,
|
||||||
|
options: {
|
||||||
|
voids?: boolean
|
||||||
|
} = {}
|
||||||
|
): Range {
|
||||||
|
const { voids = false } = options
|
||||||
let [start, end] = Range.edges(range)
|
let [start, end] = Range.edges(range)
|
||||||
|
|
||||||
// PERF: exit early if we can guarantee that the range isn't hanging.
|
// PERF: exit early if we can guarantee that the range isn't hanging.
|
||||||
@@ -22,6 +29,7 @@ export const RangeQueries = {
|
|||||||
for (const [node, path] of Editor.texts(editor, {
|
for (const [node, path] of Editor.texts(editor, {
|
||||||
at: before,
|
at: before,
|
||||||
reverse: true,
|
reverse: true,
|
||||||
|
voids,
|
||||||
})) {
|
})) {
|
||||||
if (skip) {
|
if (skip) {
|
||||||
skip = false
|
skip = false
|
||||||
|
@@ -23,11 +23,12 @@ export const NodeTransforms = {
|
|||||||
at?: Location
|
at?: Location
|
||||||
match?: NodeMatch
|
match?: NodeMatch
|
||||||
hanging?: boolean
|
hanging?: boolean
|
||||||
|
voids?: boolean
|
||||||
} = {}
|
} = {}
|
||||||
) {
|
) {
|
||||||
Editor.withoutNormalizing(editor, () => {
|
Editor.withoutNormalizing(editor, () => {
|
||||||
const { selection } = editor
|
const { selection } = editor
|
||||||
const { hanging = false } = options
|
const { hanging = false, voids = false } = options
|
||||||
let { at, match } = options
|
let { at, match } = options
|
||||||
let select = false
|
let select = false
|
||||||
|
|
||||||
@@ -41,19 +42,6 @@ export const NodeTransforms = {
|
|||||||
|
|
||||||
const [node] = nodes
|
const [node] = nodes
|
||||||
|
|
||||||
if (match == null) {
|
|
||||||
if (Path.isPath(at)) {
|
|
||||||
const path = at
|
|
||||||
match = ([, p]) => Path.equals(p, path)
|
|
||||||
} else if (Text.isText(node)) {
|
|
||||||
match = 'text'
|
|
||||||
} else if (editor.isInline(node)) {
|
|
||||||
match = ['inline', 'text']
|
|
||||||
} else {
|
|
||||||
match = 'block'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// By default, use the selection as the target location. But if there is
|
// By default, use the selection as the target location. But if there is
|
||||||
// no selection, insert at the end of the document since that is such a
|
// no selection, insert at the end of the document since that is such a
|
||||||
// common use case when inserting from a non-selected state.
|
// common use case when inserting from a non-selected state.
|
||||||
@@ -78,6 +66,16 @@ export const NodeTransforms = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Point.isPoint(at)) {
|
if (Point.isPoint(at)) {
|
||||||
|
if (match == null) {
|
||||||
|
if (Text.isText(node)) {
|
||||||
|
match = 'text'
|
||||||
|
} else if (editor.isInline(node)) {
|
||||||
|
match = ['inline', 'text']
|
||||||
|
} else {
|
||||||
|
match = 'block'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const atMatch = Editor.match(editor, at.path, match)
|
const atMatch = Editor.match(editor, at.path, match)
|
||||||
|
|
||||||
if (atMatch) {
|
if (atMatch) {
|
||||||
@@ -95,7 +93,7 @@ export const NodeTransforms = {
|
|||||||
const parentPath = Path.parent(at)
|
const parentPath = Path.parent(at)
|
||||||
let index = at[at.length - 1]
|
let index = at[at.length - 1]
|
||||||
|
|
||||||
if (Editor.match(editor, parentPath, 'void')) {
|
if (!voids && Editor.match(editor, parentPath, 'void')) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,26 +123,23 @@ export const NodeTransforms = {
|
|||||||
options: {
|
options: {
|
||||||
at?: Location
|
at?: Location
|
||||||
match?: NodeMatch
|
match?: NodeMatch
|
||||||
|
mode?: 'all' | 'highest'
|
||||||
|
voids?: boolean
|
||||||
} = {}
|
} = {}
|
||||||
) {
|
) {
|
||||||
Editor.withoutNormalizing(editor, () => {
|
Editor.withoutNormalizing(editor, () => {
|
||||||
const { at = editor.selection } = options
|
const { at = editor.selection, mode = 'highest', voids = false } = options
|
||||||
let { match } = options
|
let { match } = options
|
||||||
|
|
||||||
if (match == null) {
|
if (match == null) {
|
||||||
if (Path.isPath(at)) {
|
match = Path.isPath(at) ? matchPath(editor, at) : 'block'
|
||||||
const path = at
|
|
||||||
match = ([, p]) => Path.equals(p, path)
|
|
||||||
} else {
|
|
||||||
match = 'block'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!at) {
|
if (!at) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const matches = Editor.nodes(editor, { at, match, mode: 'highest' })
|
const matches = Editor.nodes(editor, { at, match, mode, voids })
|
||||||
const pathRefs = Array.from(matches, ([, p]) => Editor.pathRef(editor, p))
|
const pathRefs = Array.from(matches, ([, p]) => Editor.pathRef(editor, p))
|
||||||
|
|
||||||
for (const pathRef of pathRefs) {
|
for (const pathRef of pathRefs) {
|
||||||
@@ -161,15 +156,19 @@ export const NodeTransforms = {
|
|||||||
const { length } = parent.children
|
const { length } = parent.children
|
||||||
|
|
||||||
if (length === 1) {
|
if (length === 1) {
|
||||||
Editor.moveNodes(editor, { at: path, to: Path.next(parentPath) })
|
const toPath = Path.next(parentPath)
|
||||||
Editor.removeNodes(editor, { at: parentPath })
|
Editor.moveNodes(editor, { at: path, to: toPath, voids })
|
||||||
|
Editor.removeNodes(editor, { at: parentPath, voids })
|
||||||
} else if (index === 0) {
|
} else if (index === 0) {
|
||||||
Editor.moveNodes(editor, { at: path, to: parentPath })
|
Editor.moveNodes(editor, { at: path, to: parentPath, voids })
|
||||||
} else if (index === length - 1) {
|
} else if (index === length - 1) {
|
||||||
Editor.moveNodes(editor, { at: path, to: Path.next(parentPath) })
|
const toPath = Path.next(parentPath)
|
||||||
|
Editor.moveNodes(editor, { at: path, to: toPath, voids })
|
||||||
} else {
|
} else {
|
||||||
Editor.splitNodes(editor, { at: Path.next(path) })
|
const splitPath = Path.next(path)
|
||||||
Editor.moveNodes(editor, { at: path, to: Path.next(parentPath) })
|
const toPath = Path.next(parentPath)
|
||||||
|
Editor.splitNodes(editor, { at: splitPath, voids })
|
||||||
|
Editor.moveNodes(editor, { at: path, to: toPath, voids })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -186,25 +185,21 @@ export const NodeTransforms = {
|
|||||||
at?: Location
|
at?: Location
|
||||||
match?: NodeMatch
|
match?: NodeMatch
|
||||||
hanging?: boolean
|
hanging?: boolean
|
||||||
|
voids?: boolean
|
||||||
} = {}
|
} = {}
|
||||||
) {
|
) {
|
||||||
Editor.withoutNormalizing(editor, () => {
|
Editor.withoutNormalizing(editor, () => {
|
||||||
let { match, at = editor.selection } = options
|
let { match, at = editor.selection } = options
|
||||||
const { hanging = false } = options
|
const { hanging = false, voids = false } = options
|
||||||
|
|
||||||
if (match == null) {
|
|
||||||
if (Path.isPath(at)) {
|
|
||||||
const path = at
|
|
||||||
match = ([, p]) => Path.equals(p, path)
|
|
||||||
} else {
|
|
||||||
match = 'block'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!at) {
|
if (!at) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (match == null) {
|
||||||
|
match = Path.isPath(at) ? matchPath(editor, at) : 'block'
|
||||||
|
}
|
||||||
|
|
||||||
if (!hanging && Range.isRange(at)) {
|
if (!hanging && Range.isRange(at)) {
|
||||||
at = Editor.unhangRange(editor, at)
|
at = Editor.unhangRange(editor, at)
|
||||||
}
|
}
|
||||||
@@ -224,7 +219,7 @@ export const NodeTransforms = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const current = Editor.match(editor, at, match)
|
const current = Editor.match(editor, at, match, { voids })
|
||||||
|
|
||||||
if (!current) {
|
if (!current) {
|
||||||
return
|
return
|
||||||
@@ -241,7 +236,7 @@ export const NodeTransforms = {
|
|||||||
prevMatch = 'inline'
|
prevMatch = 'inline'
|
||||||
}
|
}
|
||||||
|
|
||||||
const prev = Editor.previous(editor, at, prevMatch)
|
const prev = Editor.previous(editor, at, prevMatch, { voids })
|
||||||
|
|
||||||
if (!prev) {
|
if (!prev) {
|
||||||
return
|
return
|
||||||
@@ -288,13 +283,13 @@ export const NodeTransforms = {
|
|||||||
// If the node isn't already the next sibling of the previous node, move
|
// If the node isn't already the next sibling of the previous node, move
|
||||||
// it so that it is before merging.
|
// it so that it is before merging.
|
||||||
if (!isPreviousSibling) {
|
if (!isPreviousSibling) {
|
||||||
Editor.moveNodes(editor, { at: path, to: newPath })
|
Editor.moveNodes(editor, { at: path, to: newPath, voids })
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there was going to be an empty ancestor of the node that was merged,
|
// If there was going to be an empty ancestor of the node that was merged,
|
||||||
// we remove it from the tree.
|
// we remove it from the tree.
|
||||||
if (emptyRef) {
|
if (emptyRef) {
|
||||||
Editor.removeNodes(editor, { at: emptyRef.current! })
|
Editor.removeNodes(editor, { at: emptyRef.current!, voids })
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the target node that we're merging with is empty, remove it instead
|
// If the target node that we're merging with is empty, remove it instead
|
||||||
@@ -305,7 +300,7 @@ export const NodeTransforms = {
|
|||||||
(Element.isElement(prevNode) && Editor.isEmpty(editor, prevNode)) ||
|
(Element.isElement(prevNode) && Editor.isEmpty(editor, prevNode)) ||
|
||||||
(Text.isText(prevNode) && prevNode.text === '')
|
(Text.isText(prevNode) && prevNode.text === '')
|
||||||
) {
|
) {
|
||||||
Editor.removeNodes(editor, { at: prevPath })
|
Editor.removeNodes(editor, { at: prevPath, voids })
|
||||||
} else {
|
} else {
|
||||||
editor.apply({
|
editor.apply({
|
||||||
type: 'merge_node',
|
type: 'merge_node',
|
||||||
@@ -331,28 +326,30 @@ export const NodeTransforms = {
|
|||||||
options: {
|
options: {
|
||||||
at?: Location
|
at?: Location
|
||||||
match?: NodeMatch
|
match?: NodeMatch
|
||||||
|
mode?: 'all' | 'highest'
|
||||||
to: Path
|
to: Path
|
||||||
|
voids?: boolean
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
Editor.withoutNormalizing(editor, () => {
|
Editor.withoutNormalizing(editor, () => {
|
||||||
const { to, at = editor.selection } = options
|
const {
|
||||||
|
to,
|
||||||
|
at = editor.selection,
|
||||||
|
mode = 'highest',
|
||||||
|
voids = false,
|
||||||
|
} = options
|
||||||
let { match } = options
|
let { match } = options
|
||||||
|
|
||||||
if (match == null) {
|
|
||||||
if (Path.isPath(at)) {
|
|
||||||
const path = at
|
|
||||||
match = ([, p]) => Path.equals(p, path)
|
|
||||||
} else {
|
|
||||||
match = 'block'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!at) {
|
if (!at) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (match == null) {
|
||||||
|
match = Path.isPath(at) ? matchPath(editor, at) : 'block'
|
||||||
|
}
|
||||||
|
|
||||||
const toRef = Editor.pathRef(editor, to)
|
const toRef = Editor.pathRef(editor, to)
|
||||||
const targets = Editor.nodes(editor, { at, match, mode: 'highest' })
|
const targets = Editor.nodes(editor, { at, match, mode, voids })
|
||||||
const pathRefs = Array.from(targets, ([, p]) => Editor.pathRef(editor, p))
|
const pathRefs = Array.from(targets, ([, p]) => Editor.pathRef(editor, p))
|
||||||
|
|
||||||
for (const pathRef of pathRefs) {
|
for (const pathRef of pathRefs) {
|
||||||
@@ -377,37 +374,41 @@ export const NodeTransforms = {
|
|||||||
options: {
|
options: {
|
||||||
at?: Location
|
at?: Location
|
||||||
match?: NodeMatch
|
match?: NodeMatch
|
||||||
|
mode?: 'all' | 'highest'
|
||||||
hanging?: boolean
|
hanging?: boolean
|
||||||
|
voids?: boolean
|
||||||
} = {}
|
} = {}
|
||||||
) {
|
) {
|
||||||
Editor.withoutNormalizing(editor, () => {
|
Editor.withoutNormalizing(editor, () => {
|
||||||
let { match, at = editor.selection } = options
|
const { hanging = false, voids = false } = options
|
||||||
const { hanging = false } = options
|
let { at = editor.selection, mode, match } = options
|
||||||
|
|
||||||
if (match == null) {
|
|
||||||
if (Path.isPath(at)) {
|
|
||||||
const path = at
|
|
||||||
match = ([, p]) => Path.equals(p, path)
|
|
||||||
} else {
|
|
||||||
match = 'block'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!at) {
|
if (!at) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (match == null) {
|
||||||
|
match = Path.isPath(at) ? matchPath(editor, at) : 'block'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == null || mode === 'all') {
|
||||||
|
mode = 'highest'
|
||||||
|
}
|
||||||
|
|
||||||
if (!hanging && Range.isRange(at)) {
|
if (!hanging && Range.isRange(at)) {
|
||||||
at = Editor.unhangRange(editor, at)
|
at = Editor.unhangRange(editor, at)
|
||||||
}
|
}
|
||||||
|
|
||||||
const depths = Editor.nodes(editor, { at, match, mode: 'highest' })
|
const depths = Editor.nodes(editor, { at, match, mode, voids })
|
||||||
const pathRefs = Array.from(depths, ([, p]) => Editor.pathRef(editor, p))
|
const pathRefs = Array.from(depths, ([, p]) => Editor.pathRef(editor, p))
|
||||||
|
|
||||||
for (const pathRef of pathRefs) {
|
for (const pathRef of pathRefs) {
|
||||||
const path = pathRef.unref()!
|
const path = pathRef.unref()!
|
||||||
const [node] = Editor.node(editor, path)
|
|
||||||
editor.apply({ type: 'remove_node', path, node })
|
if (path) {
|
||||||
|
const [node] = Editor.node(editor, path)
|
||||||
|
editor.apply({ type: 'remove_node', path, node })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -425,25 +426,26 @@ export const NodeTransforms = {
|
|||||||
mode?: 'all' | 'highest'
|
mode?: 'all' | 'highest'
|
||||||
hanging?: boolean
|
hanging?: boolean
|
||||||
split?: boolean
|
split?: boolean
|
||||||
|
voids?: boolean
|
||||||
} = {}
|
} = {}
|
||||||
) {
|
) {
|
||||||
Editor.withoutNormalizing(editor, () => {
|
Editor.withoutNormalizing(editor, () => {
|
||||||
let { match, at = editor.selection } = options
|
let { match, at = editor.selection } = options
|
||||||
const { hanging = false, mode = 'highest', split = false } = options
|
const {
|
||||||
|
hanging = false,
|
||||||
if (match == null) {
|
mode = 'highest',
|
||||||
if (Path.isPath(at)) {
|
split = false,
|
||||||
const path = at
|
voids = false,
|
||||||
match = ([, p]) => Path.equals(p, path)
|
} = options
|
||||||
} else {
|
|
||||||
match = 'block'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!at) {
|
if (!at) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (match == null) {
|
||||||
|
match = Path.isPath(at) ? matchPath(editor, at) : 'block'
|
||||||
|
}
|
||||||
|
|
||||||
if (!hanging && Range.isRange(at)) {
|
if (!hanging && Range.isRange(at)) {
|
||||||
at = Editor.unhangRange(editor, at)
|
at = Editor.unhangRange(editor, at)
|
||||||
}
|
}
|
||||||
@@ -451,8 +453,8 @@ export const NodeTransforms = {
|
|||||||
if (split && Range.isRange(at)) {
|
if (split && Range.isRange(at)) {
|
||||||
const rangeRef = Editor.rangeRef(editor, at, { affinity: 'inward' })
|
const rangeRef = Editor.rangeRef(editor, at, { affinity: 'inward' })
|
||||||
const [start, end] = Range.edges(at)
|
const [start, end] = Range.edges(at)
|
||||||
Editor.splitNodes(editor, { at: end, match })
|
Editor.splitNodes(editor, { at: end, match, voids })
|
||||||
Editor.splitNodes(editor, { at: start, match })
|
Editor.splitNodes(editor, { at: start, match, voids })
|
||||||
at = rangeRef.unref()!
|
at = rangeRef.unref()!
|
||||||
|
|
||||||
if (options.at == null) {
|
if (options.at == null) {
|
||||||
@@ -460,7 +462,12 @@ export const NodeTransforms = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [node, path] of Editor.nodes(editor, { at, match, mode })) {
|
for (const [node, path] of Editor.nodes(editor, {
|
||||||
|
at,
|
||||||
|
match,
|
||||||
|
mode,
|
||||||
|
voids,
|
||||||
|
})) {
|
||||||
const properties: Partial<Node> = {}
|
const properties: Partial<Node> = {}
|
||||||
const newProperties: Partial<Node> = {}
|
const newProperties: Partial<Node> = {}
|
||||||
|
|
||||||
@@ -503,10 +510,17 @@ export const NodeTransforms = {
|
|||||||
match?: NodeMatch
|
match?: NodeMatch
|
||||||
always?: boolean
|
always?: boolean
|
||||||
height?: number
|
height?: number
|
||||||
|
voids?: boolean
|
||||||
} = {}
|
} = {}
|
||||||
) {
|
) {
|
||||||
Editor.withoutNormalizing(editor, () => {
|
Editor.withoutNormalizing(editor, () => {
|
||||||
let { match, at = editor.selection, height = 0, always = false } = options
|
let {
|
||||||
|
match,
|
||||||
|
at = editor.selection,
|
||||||
|
height = 0,
|
||||||
|
always = false,
|
||||||
|
voids = false,
|
||||||
|
} = options
|
||||||
|
|
||||||
if (match == null) {
|
if (match == null) {
|
||||||
match = 'block'
|
match = 'block'
|
||||||
@@ -534,7 +548,7 @@ export const NodeTransforms = {
|
|||||||
const beforeRef = Editor.pointRef(editor, at, {
|
const beforeRef = Editor.pointRef(editor, at, {
|
||||||
affinity: 'backward',
|
affinity: 'backward',
|
||||||
})
|
})
|
||||||
const highest = Editor.match(editor, at, match)
|
const highest = Editor.match(editor, at, match, { voids })
|
||||||
|
|
||||||
if (!highest) {
|
if (!highest) {
|
||||||
return
|
return
|
||||||
@@ -543,7 +557,7 @@ export const NodeTransforms = {
|
|||||||
const voidMatch = Editor.match(editor, at, 'void')
|
const voidMatch = Editor.match(editor, at, 'void')
|
||||||
const nudge = 0
|
const nudge = 0
|
||||||
|
|
||||||
if (voidMatch) {
|
if (!voids && voidMatch) {
|
||||||
const [voidNode, voidPath] = voidMatch
|
const [voidNode, voidPath] = voidMatch
|
||||||
|
|
||||||
if (Element.isElement(voidNode) && editor.isInline(voidNode)) {
|
if (Element.isElement(voidNode) && editor.isInline(voidNode)) {
|
||||||
@@ -552,7 +566,7 @@ export const NodeTransforms = {
|
|||||||
if (!after) {
|
if (!after) {
|
||||||
const text = { text: '' }
|
const text = { text: '' }
|
||||||
const afterPath = Path.next(voidPath)
|
const afterPath = Path.next(voidPath)
|
||||||
Editor.insertNodes(editor, text, { at: afterPath })
|
Editor.insertNodes(editor, text, { at: afterPath, voids })
|
||||||
after = Editor.point(editor, afterPath)!
|
after = Editor.point(editor, afterPath)!
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -575,13 +589,14 @@ export const NodeTransforms = {
|
|||||||
for (const [node, path] of Editor.levels(editor, {
|
for (const [node, path] of Editor.levels(editor, {
|
||||||
at: lowestPath,
|
at: lowestPath,
|
||||||
reverse: true,
|
reverse: true,
|
||||||
|
voids,
|
||||||
})) {
|
})) {
|
||||||
let split = false
|
let split = false
|
||||||
|
|
||||||
if (
|
if (
|
||||||
path.length < highestPath.length ||
|
path.length < highestPath.length ||
|
||||||
path.length === 0 ||
|
path.length === 0 ||
|
||||||
(Element.isElement(node) && editor.isVoid(node))
|
(!voids && Element.isElement(node) && editor.isVoid(node))
|
||||||
) {
|
) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -625,27 +640,29 @@ export const NodeTransforms = {
|
|||||||
options: {
|
options: {
|
||||||
at?: Location
|
at?: Location
|
||||||
match?: NodeMatch
|
match?: NodeMatch
|
||||||
|
mode?: 'all' | 'highest'
|
||||||
split?: boolean
|
split?: boolean
|
||||||
|
voids?: boolean
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
Editor.withoutNormalizing(editor, () => {
|
Editor.withoutNormalizing(editor, () => {
|
||||||
const { at = editor.selection, split = false } = options
|
const {
|
||||||
|
at = editor.selection,
|
||||||
|
mode = 'highest',
|
||||||
|
split = false,
|
||||||
|
voids = false,
|
||||||
|
} = options
|
||||||
let { match } = options
|
let { match } = options
|
||||||
|
|
||||||
if (match == null) {
|
|
||||||
if (Path.isPath(at)) {
|
|
||||||
const path = at
|
|
||||||
match = ([, p]) => Path.equals(p, path)
|
|
||||||
} else {
|
|
||||||
match = 'block'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!at) {
|
if (!at) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const matches = Editor.nodes(editor, { at, match, mode: 'highest' })
|
if (match == null) {
|
||||||
|
match = Path.isPath(at) ? matchPath(editor, at) : 'block'
|
||||||
|
}
|
||||||
|
|
||||||
|
const matches = Editor.nodes(editor, { at, match, mode, voids })
|
||||||
const pathRefs = Array.from(matches, ([, p]) => Editor.pathRef(editor, p))
|
const pathRefs = Array.from(matches, ([, p]) => Editor.pathRef(editor, p))
|
||||||
|
|
||||||
for (const pathRef of pathRefs) {
|
for (const pathRef of pathRefs) {
|
||||||
@@ -660,6 +677,7 @@ export const NodeTransforms = {
|
|||||||
Editor.liftNodes(editor, {
|
Editor.liftNodes(editor, {
|
||||||
at: range,
|
at: range,
|
||||||
match: ([, p]) => p.length === depth,
|
match: ([, p]) => p.length === depth,
|
||||||
|
voids,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -676,11 +694,13 @@ export const NodeTransforms = {
|
|||||||
options: {
|
options: {
|
||||||
at?: Location
|
at?: Location
|
||||||
match?: NodeMatch
|
match?: NodeMatch
|
||||||
|
mode?: 'all' | 'highest'
|
||||||
split?: boolean
|
split?: boolean
|
||||||
|
voids?: boolean
|
||||||
} = {}
|
} = {}
|
||||||
) {
|
) {
|
||||||
Editor.withoutNormalizing(editor, () => {
|
Editor.withoutNormalizing(editor, () => {
|
||||||
const { split = false } = options
|
const { mode = 'highest', split = false, voids = false } = options
|
||||||
let { match, at = editor.selection } = options
|
let { match, at = editor.selection } = options
|
||||||
|
|
||||||
if (!at) {
|
if (!at) {
|
||||||
@@ -689,8 +709,7 @@ export const NodeTransforms = {
|
|||||||
|
|
||||||
if (match == null) {
|
if (match == null) {
|
||||||
if (Path.isPath(at)) {
|
if (Path.isPath(at)) {
|
||||||
const path = at
|
match = matchPath(editor, at)
|
||||||
match = ([, p]) => Path.equals(p, path)
|
|
||||||
} else if (editor.isInline(element)) {
|
} else if (editor.isInline(element)) {
|
||||||
match = ['inline', 'text']
|
match = ['inline', 'text']
|
||||||
} else {
|
} else {
|
||||||
@@ -703,8 +722,8 @@ export const NodeTransforms = {
|
|||||||
const rangeRef = Editor.rangeRef(editor, at, {
|
const rangeRef = Editor.rangeRef(editor, at, {
|
||||||
affinity: 'inward',
|
affinity: 'inward',
|
||||||
})
|
})
|
||||||
Editor.splitNodes(editor, { at: end, match })
|
Editor.splitNodes(editor, { at: end, match, voids })
|
||||||
Editor.splitNodes(editor, { at: start, match })
|
Editor.splitNodes(editor, { at: start, match, voids })
|
||||||
at = rangeRef.unref()!
|
at = rangeRef.unref()!
|
||||||
|
|
||||||
if (options.at == null) {
|
if (options.at == null) {
|
||||||
@@ -712,16 +731,14 @@ export const NodeTransforms = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const roots: NodeEntry[] = editor.isInline(element)
|
const roots = Array.from(
|
||||||
? Array.from(
|
Editor.nodes(editor, {
|
||||||
Editor.nodes(editor, {
|
at,
|
||||||
...options,
|
match: editor.isInline(element) ? 'block' : 'editor',
|
||||||
at,
|
mode: 'highest',
|
||||||
match: 'block',
|
voids,
|
||||||
mode: 'highest',
|
})
|
||||||
})
|
)
|
||||||
)
|
|
||||||
: [[editor, []]]
|
|
||||||
|
|
||||||
for (const [, rootPath] of roots) {
|
for (const [, rootPath] of roots) {
|
||||||
const a = Range.isRange(at)
|
const a = Range.isRange(at)
|
||||||
@@ -733,7 +750,7 @@ export const NodeTransforms = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const matches = Array.from(
|
const matches = Array.from(
|
||||||
Editor.nodes(editor, { ...options, at: a, match, mode: 'highest' })
|
Editor.nodes(editor, { at: a, match, mode, voids })
|
||||||
)
|
)
|
||||||
|
|
||||||
if (matches.length > 0) {
|
if (matches.length > 0) {
|
||||||
@@ -749,12 +766,13 @@ export const NodeTransforms = {
|
|||||||
const depth = commonPath.length + 1
|
const depth = commonPath.length + 1
|
||||||
const wrapperPath = Path.next(lastPath).slice(0, depth)
|
const wrapperPath = Path.next(lastPath).slice(0, depth)
|
||||||
const wrapper = { ...element, children: [] }
|
const wrapper = { ...element, children: [] }
|
||||||
Editor.insertNodes(editor, wrapper, { at: wrapperPath })
|
Editor.insertNodes(editor, wrapper, { at: wrapperPath, voids })
|
||||||
|
|
||||||
Editor.moveNodes(editor, {
|
Editor.moveNodes(editor, {
|
||||||
at: range,
|
at: range,
|
||||||
match: ([, p]) => p.length === depth,
|
match: ([, p]) => p.length === depth,
|
||||||
to: wrapperPath.concat(0),
|
to: wrapperPath.concat(0),
|
||||||
|
voids,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -776,3 +794,11 @@ const deleteRange = (editor: Editor, range: Range): Point | null => {
|
|||||||
return pointRef.unref()
|
return pointRef.unref()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const matchPath = (
|
||||||
|
editor: Editor,
|
||||||
|
path: Path
|
||||||
|
): ((entry: NodeEntry) => boolean) => {
|
||||||
|
const [node] = Editor.node(editor, path)
|
||||||
|
return ([n]) => n === node
|
||||||
|
}
|
||||||
|
@@ -22,10 +22,16 @@ export const TextTransforms = {
|
|||||||
unit?: 'character' | 'word' | 'line' | 'block'
|
unit?: 'character' | 'word' | 'line' | 'block'
|
||||||
reverse?: boolean
|
reverse?: boolean
|
||||||
hanging?: boolean
|
hanging?: boolean
|
||||||
|
voids?: boolean
|
||||||
} = {}
|
} = {}
|
||||||
) {
|
) {
|
||||||
Editor.withoutNormalizing(editor, () => {
|
Editor.withoutNormalizing(editor, () => {
|
||||||
const { reverse = false, unit = 'character', distance = 1 } = options
|
const {
|
||||||
|
reverse = false,
|
||||||
|
unit = 'character',
|
||||||
|
distance = 1,
|
||||||
|
voids = false,
|
||||||
|
} = options
|
||||||
let { at = editor.selection, hanging = false } = options
|
let { at = editor.selection, hanging = false } = options
|
||||||
|
|
||||||
if (!at) {
|
if (!at) {
|
||||||
@@ -39,7 +45,7 @@ export const TextTransforms = {
|
|||||||
if (Point.isPoint(at)) {
|
if (Point.isPoint(at)) {
|
||||||
const furthestVoid = Editor.match(editor, at.path, 'void')
|
const furthestVoid = Editor.match(editor, at.path, 'void')
|
||||||
|
|
||||||
if (furthestVoid) {
|
if (!voids && furthestVoid) {
|
||||||
const [, voidPath] = furthestVoid
|
const [, voidPath] = furthestVoid
|
||||||
at = voidPath
|
at = voidPath
|
||||||
} else {
|
} else {
|
||||||
@@ -53,7 +59,7 @@ export const TextTransforms = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Path.isPath(at)) {
|
if (Path.isPath(at)) {
|
||||||
Editor.removeNodes(editor, { at })
|
Editor.removeNodes(editor, { at, voids })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,17 +68,17 @@ export const TextTransforms = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!hanging) {
|
if (!hanging) {
|
||||||
at = Editor.unhangRange(editor, at)
|
at = Editor.unhangRange(editor, at, { voids })
|
||||||
}
|
}
|
||||||
|
|
||||||
let [start, end] = Range.edges(at)
|
let [start, end] = Range.edges(at)
|
||||||
const startBlock = Editor.match(editor, start.path, 'block')
|
const startBlock = Editor.match(editor, start.path, 'block', { voids })
|
||||||
const endBlock = Editor.match(editor, end.path, 'block')
|
const endBlock = Editor.match(editor, end.path, 'block', { voids })
|
||||||
const isAcrossBlocks =
|
const isAcrossBlocks =
|
||||||
startBlock && endBlock && !Path.equals(startBlock[1], endBlock[1])
|
startBlock && endBlock && !Path.equals(startBlock[1], endBlock[1])
|
||||||
const isSingleText = Path.equals(start.path, end.path)
|
const isSingleText = Path.equals(start.path, end.path)
|
||||||
const startVoid = Editor.match(editor, start.path, 'void')
|
const startVoid = voids ? null : Editor.match(editor, start.path, 'void')
|
||||||
const endVoid = Editor.match(editor, end.path, 'void')
|
const endVoid = voids ? null : Editor.match(editor, end.path, 'void')
|
||||||
|
|
||||||
// If the start or end points are inside an inline void, nudge them out.
|
// If the start or end points are inside an inline void, nudge them out.
|
||||||
if (startVoid) {
|
if (startVoid) {
|
||||||
@@ -99,9 +105,10 @@ export const TextTransforms = {
|
|||||||
// the start and end nodes.
|
// the start and end nodes.
|
||||||
const matches = Editor.nodes(editor, {
|
const matches = Editor.nodes(editor, {
|
||||||
at,
|
at,
|
||||||
|
voids,
|
||||||
mode: 'highest',
|
mode: 'highest',
|
||||||
match: ([n, p]) =>
|
match: ([n, p]) =>
|
||||||
(Element.isElement(n) && editor.isVoid(n)) ||
|
(!voids && Element.isElement(n) && editor.isVoid(n)) ||
|
||||||
(!Path.isCommon(p, start.path) && !Path.isCommon(p, end.path)),
|
(!Path.isCommon(p, start.path) && !Path.isCommon(p, end.path)),
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -120,7 +127,7 @@ export const TextTransforms = {
|
|||||||
|
|
||||||
for (const pathRef of pathRefs) {
|
for (const pathRef of pathRefs) {
|
||||||
const path = pathRef.unref()!
|
const path = pathRef.unref()!
|
||||||
Editor.removeNodes(editor, { at: path })
|
Editor.removeNodes(editor, { at: path, voids })
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!endVoid) {
|
if (!endVoid) {
|
||||||
@@ -138,7 +145,11 @@ export const TextTransforms = {
|
|||||||
endRef.current &&
|
endRef.current &&
|
||||||
startRef.current
|
startRef.current
|
||||||
) {
|
) {
|
||||||
Editor.mergeNodes(editor, { at: endRef.current, hanging: true })
|
Editor.mergeNodes(editor, {
|
||||||
|
at: endRef.current,
|
||||||
|
hanging: true,
|
||||||
|
voids,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const point = endRef.unref() || startRef.unref()
|
const point = endRef.unref() || startRef.unref()
|
||||||
@@ -159,11 +170,12 @@ export const TextTransforms = {
|
|||||||
options: {
|
options: {
|
||||||
at?: Location
|
at?: Location
|
||||||
hanging?: boolean
|
hanging?: boolean
|
||||||
|
voids?: boolean
|
||||||
} = {}
|
} = {}
|
||||||
) {
|
) {
|
||||||
Editor.withoutNormalizing(editor, () => {
|
Editor.withoutNormalizing(editor, () => {
|
||||||
|
const { hanging = false, voids = false } = options
|
||||||
let { at = editor.selection } = options
|
let { at = editor.selection } = options
|
||||||
const { hanging = false } = options
|
|
||||||
|
|
||||||
if (!fragment.length) {
|
if (!fragment.length) {
|
||||||
return
|
return
|
||||||
@@ -180,6 +192,11 @@ export const TextTransforms = {
|
|||||||
at = at.anchor
|
at = at.anchor
|
||||||
} else {
|
} else {
|
||||||
const [, end] = Range.edges(at)
|
const [, end] = Range.edges(at)
|
||||||
|
|
||||||
|
if (!voids && Editor.match(editor, end, 'void')) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const pointRef = Editor.pointRef(editor, end)
|
const pointRef = Editor.pointRef(editor, end)
|
||||||
Editor.delete(editor, { at })
|
Editor.delete(editor, { at })
|
||||||
at = pointRef.unref()!
|
at = pointRef.unref()!
|
||||||
@@ -188,13 +205,13 @@ export const TextTransforms = {
|
|||||||
at = Editor.start(editor, at)
|
at = Editor.start(editor, at)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Editor.match(editor, at.path, 'void')) {
|
if (!voids && Editor.match(editor, at.path, 'void')) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the insert point is at the edge of an inline node, move it outside
|
// If the insert point is at the edge of an inline node, move it outside
|
||||||
// instead since it will need to be split otherwise.
|
// instead since it will need to be split otherwise.
|
||||||
const inlineElementMatch = Editor.match(editor, at, 'inline')
|
const inlineElementMatch = Editor.match(editor, at, 'inline', { voids })
|
||||||
|
|
||||||
if (inlineElementMatch) {
|
if (inlineElementMatch) {
|
||||||
const [, inlinePath] = inlineElementMatch
|
const [, inlinePath] = inlineElementMatch
|
||||||
@@ -208,7 +225,7 @@ export const TextTransforms = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const blockMatch = Editor.match(editor, at, 'block')!
|
const blockMatch = Editor.match(editor, at, 'block', { voids })!
|
||||||
const [, blockPath] = blockMatch
|
const [, blockPath] = blockMatch
|
||||||
const isBlockStart = Editor.isStart(editor, at, blockPath)
|
const isBlockStart = Editor.isStart(editor, at, blockPath)
|
||||||
const isBlockEnd = Editor.isEnd(editor, at, blockPath)
|
const isBlockEnd = Editor.isEnd(editor, at, blockPath)
|
||||||
@@ -217,9 +234,7 @@ export const TextTransforms = {
|
|||||||
const [, firstPath] = Node.first({ children: fragment }, [])
|
const [, firstPath] = Node.first({ children: fragment }, [])
|
||||||
const [, lastPath] = Node.last({ children: fragment }, [])
|
const [, lastPath] = Node.last({ children: fragment }, [])
|
||||||
|
|
||||||
// TODO: convert into a proper `Nodes.matches` iterable
|
|
||||||
const matches: NodeEntry[] = []
|
const matches: NodeEntry[] = []
|
||||||
|
|
||||||
const matcher = ([n, p]: NodeEntry) => {
|
const matcher = ([n, p]: NodeEntry) => {
|
||||||
if (
|
if (
|
||||||
mergeStart &&
|
mergeStart &&
|
||||||
@@ -271,7 +286,9 @@ export const TextTransforms = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const inlineMatch = Editor.match(editor, at, ['inline', 'text'])!
|
const inlineMatch = Editor.match(editor, at, ['inline', 'text'], {
|
||||||
|
voids,
|
||||||
|
})!
|
||||||
const [, inlinePath] = inlineMatch
|
const [, inlinePath] = inlineMatch
|
||||||
const isInlineStart = Editor.isStart(editor, at, inlinePath)
|
const isInlineStart = Editor.isStart(editor, at, inlinePath)
|
||||||
const isInlineEnd = Editor.isEnd(editor, at, inlinePath)
|
const isInlineEnd = Editor.isEnd(editor, at, inlinePath)
|
||||||
@@ -289,6 +306,7 @@ export const TextTransforms = {
|
|||||||
Editor.splitNodes(editor, {
|
Editor.splitNodes(editor, {
|
||||||
at,
|
at,
|
||||||
match: hasBlocks ? 'block' : ['inline', 'text'],
|
match: hasBlocks ? 'block' : ['inline', 'text'],
|
||||||
|
voids,
|
||||||
})
|
})
|
||||||
|
|
||||||
const startRef = Editor.pathRef(
|
const startRef = Editor.pathRef(
|
||||||
@@ -301,16 +319,19 @@ export const TextTransforms = {
|
|||||||
Editor.insertNodes(editor, starts, {
|
Editor.insertNodes(editor, starts, {
|
||||||
at: startRef.current!,
|
at: startRef.current!,
|
||||||
match: ['inline', 'text'],
|
match: ['inline', 'text'],
|
||||||
|
voids,
|
||||||
})
|
})
|
||||||
|
|
||||||
Editor.insertNodes(editor, middles, {
|
Editor.insertNodes(editor, middles, {
|
||||||
at: middleRef.current!,
|
at: middleRef.current!,
|
||||||
match: 'block',
|
match: 'block',
|
||||||
|
voids,
|
||||||
})
|
})
|
||||||
|
|
||||||
Editor.insertNodes(editor, ends, {
|
Editor.insertNodes(editor, ends, {
|
||||||
at: endRef.current!,
|
at: endRef.current!,
|
||||||
match: ['inline', 'text'],
|
match: ['inline', 'text'],
|
||||||
|
voids,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!options.at) {
|
if (!options.at) {
|
||||||
@@ -343,9 +364,11 @@ export const TextTransforms = {
|
|||||||
text: string,
|
text: string,
|
||||||
options: {
|
options: {
|
||||||
at?: Location
|
at?: Location
|
||||||
|
voids?: boolean
|
||||||
} = {}
|
} = {}
|
||||||
) {
|
) {
|
||||||
Editor.withoutNormalizing(editor, () => {
|
Editor.withoutNormalizing(editor, () => {
|
||||||
|
const { voids = false } = options
|
||||||
let { at = editor.selection } = options
|
let { at = editor.selection } = options
|
||||||
|
|
||||||
if (!at) {
|
if (!at) {
|
||||||
@@ -360,13 +383,19 @@ export const TextTransforms = {
|
|||||||
if (Range.isCollapsed(at)) {
|
if (Range.isCollapsed(at)) {
|
||||||
at = at.anchor
|
at = at.anchor
|
||||||
} else {
|
} else {
|
||||||
const pointRef = Editor.pointRef(editor, Range.end(at))
|
const end = Range.end(at)
|
||||||
Editor.delete(editor, { at })
|
|
||||||
|
if (!voids && Editor.match(editor, end, 'void')) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const pointRef = Editor.pointRef(editor, end)
|
||||||
|
Editor.delete(editor, { at, voids })
|
||||||
at = pointRef.unref()!
|
at = pointRef.unref()!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Editor.match(editor, at.path, 'void')) {
|
if (!voids && Editor.match(editor, at.path, 'void')) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
18
packages/slate/test/queries/nodes/voids-true/block.js
Normal file
18
packages/slate/test/queries/nodes/voids-true/block.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block void>one</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const run = editor => {
|
||||||
|
return Array.from(
|
||||||
|
Editor.nodes(editor, { at: [], match: 'text', voids: true })
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const output = [[<text>one</text>, [0, 0]]]
|
24
packages/slate/test/queries/nodes/voids-true/inline.js
Normal file
24
packages/slate/test/queries/nodes/voids-true/inline.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block>
|
||||||
|
one<inline void>two</inline>three
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const run = editor => {
|
||||||
|
return Array.from(
|
||||||
|
Editor.nodes(editor, { at: [], match: 'text', voids: true })
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const output = [
|
||||||
|
[<text>one</text>, [0, 0]],
|
||||||
|
[<text>two</text>, [0, 1, 0]],
|
||||||
|
[<text>three</text>, [0, 2]],
|
||||||
|
]
|
@@ -0,0 +1,35 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block void>
|
||||||
|
<text>
|
||||||
|
on
|
||||||
|
<anchor />e
|
||||||
|
</text>
|
||||||
|
</block>
|
||||||
|
<block void>
|
||||||
|
<text>
|
||||||
|
t<focus />
|
||||||
|
wo
|
||||||
|
</text>
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const run = editor => {
|
||||||
|
Editor.delete(editor, { voids: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const output = (
|
||||||
|
<editor>
|
||||||
|
<block void>
|
||||||
|
on
|
||||||
|
<cursor />
|
||||||
|
wo
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
24
packages/slate/test/transforms/delete/voids-true/path.js
Normal file
24
packages/slate/test/transforms/delete/voids-true/path.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block void>
|
||||||
|
<text>one</text>
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const run = editor => {
|
||||||
|
Editor.delete(editor, { at: [0, 0], voids: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const output = (
|
||||||
|
<editor>
|
||||||
|
<block void>
|
||||||
|
<text />
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
@@ -0,0 +1,28 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const run = editor => {
|
||||||
|
Editor.insertFragment(editor, <fragment>fragment</fragment>)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block void>
|
||||||
|
wo
|
||||||
|
<cursor />
|
||||||
|
rd
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const output = (
|
||||||
|
<editor>
|
||||||
|
<block void>
|
||||||
|
wo
|
||||||
|
<cursor />
|
||||||
|
rd
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
@@ -0,0 +1,37 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const run = editor => {
|
||||||
|
Editor.insertFragment(editor, <fragment>fragment</fragment>)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block>
|
||||||
|
<text />
|
||||||
|
<inline void>
|
||||||
|
wo
|
||||||
|
<cursor />
|
||||||
|
rd
|
||||||
|
</inline>
|
||||||
|
<text />
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: argument to made that fragment should go into the inline
|
||||||
|
export const output = (
|
||||||
|
<editor>
|
||||||
|
<block>
|
||||||
|
<text />
|
||||||
|
<inline void>
|
||||||
|
wo
|
||||||
|
<cursor />
|
||||||
|
rd
|
||||||
|
</inline>
|
||||||
|
<text />
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
@@ -0,0 +1,28 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const run = editor => {
|
||||||
|
Editor.insertFragment(editor, <fragment>fragment</fragment>, { voids: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block void>
|
||||||
|
wo
|
||||||
|
<cursor />
|
||||||
|
rd
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const output = (
|
||||||
|
<editor>
|
||||||
|
<block void>
|
||||||
|
wofragment
|
||||||
|
<cursor />
|
||||||
|
rd
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
@@ -0,0 +1,36 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const run = editor => {
|
||||||
|
Editor.insertFragment(editor, <fragment>fragment</fragment>, { voids: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block>
|
||||||
|
<text />
|
||||||
|
<inline void>
|
||||||
|
wo
|
||||||
|
<cursor />
|
||||||
|
rd
|
||||||
|
</inline>
|
||||||
|
<text />
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: argument to made that fragment should go into the inline
|
||||||
|
export const output = (
|
||||||
|
<editor>
|
||||||
|
<block>
|
||||||
|
<text />
|
||||||
|
<inline void>wo</inline>
|
||||||
|
fragment
|
||||||
|
<cursor />
|
||||||
|
<inline void>rd</inline>
|
||||||
|
<text />
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
@@ -0,0 +1,29 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block void>
|
||||||
|
one
|
||||||
|
<cursor />
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const run = editor => {
|
||||||
|
Editor.insertNodes(editor, <text>two</text>, {
|
||||||
|
at: [0, 1],
|
||||||
|
voids: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const output = (
|
||||||
|
<editor>
|
||||||
|
<block void>
|
||||||
|
onetwo
|
||||||
|
<cursor />
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
@@ -0,0 +1,37 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block>
|
||||||
|
one
|
||||||
|
<inline void>
|
||||||
|
two
|
||||||
|
<cursor />
|
||||||
|
</inline>
|
||||||
|
three
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const run = editor => {
|
||||||
|
Editor.insertNodes(editor, <text>four</text>, {
|
||||||
|
at: [0, 1, 1],
|
||||||
|
voids: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const output = (
|
||||||
|
<editor>
|
||||||
|
<block>
|
||||||
|
one
|
||||||
|
<inline void>
|
||||||
|
twofour
|
||||||
|
<cursor />
|
||||||
|
</inline>
|
||||||
|
three
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
@@ -0,0 +1,20 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block void>word</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const run = editor => {
|
||||||
|
Editor.insertText(editor, 'x', { at: [0] })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const output = (
|
||||||
|
<editor>
|
||||||
|
<block void>word</block>
|
||||||
|
</editor>
|
||||||
|
)
|
@@ -0,0 +1,20 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block void>word</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const run = editor => {
|
||||||
|
Editor.insertText(editor, 'x', { at: [0, 0] })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const output = (
|
||||||
|
<editor>
|
||||||
|
<block void>word</block>
|
||||||
|
</editor>
|
||||||
|
)
|
@@ -0,0 +1,20 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block void>word</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const run = editor => {
|
||||||
|
Editor.insertText(editor, 'x', { at: [0], voids: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const output = (
|
||||||
|
<editor>
|
||||||
|
<block void>x</block>
|
||||||
|
</editor>
|
||||||
|
)
|
20
packages/slate/test/transforms/insertText/voids-true/text.js
Normal file
20
packages/slate/test/transforms/insertText/voids-true/text.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block void>word</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const run = editor => {
|
||||||
|
Editor.insertText(editor, 'x', { at: [0, 0], voids: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const output = (
|
||||||
|
<editor>
|
||||||
|
<block void>x</block>
|
||||||
|
</editor>
|
||||||
|
)
|
22
packages/slate/test/transforms/liftNodes/voids-true/block.js
Normal file
22
packages/slate/test/transforms/liftNodes/voids-true/block.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const run = editor => {
|
||||||
|
Editor.liftNodes(editor, { at: [0, 0], voids: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block void>
|
||||||
|
<block>word</block>
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const output = (
|
||||||
|
<editor>
|
||||||
|
<block>word</block>
|
||||||
|
</editor>
|
||||||
|
)
|
@@ -0,0 +1,23 @@
|
|||||||
|
/** @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 run = editor => {
|
||||||
|
Editor.mergeNodes(editor, { at: [0, 1], voids: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const output = (
|
||||||
|
<editor>
|
||||||
|
<block void>onetwo</block>
|
||||||
|
</editor>
|
||||||
|
)
|
28
packages/slate/test/transforms/moveNodes/voids-true/block.js
Normal file
28
packages/slate/test/transforms/moveNodes/voids-true/block.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block void>one</block>
|
||||||
|
<block void>two</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const run = editor => {
|
||||||
|
Editor.moveNodes(editor, {
|
||||||
|
at: [0, 0],
|
||||||
|
to: [1, 0],
|
||||||
|
voids: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const output = (
|
||||||
|
<editor>
|
||||||
|
<block void>
|
||||||
|
<text />
|
||||||
|
</block>
|
||||||
|
<block void>onetwo</block>
|
||||||
|
</editor>
|
||||||
|
)
|
@@ -0,0 +1,38 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block>
|
||||||
|
<text />
|
||||||
|
<inline>
|
||||||
|
<cursor />
|
||||||
|
one
|
||||||
|
</inline>
|
||||||
|
<text />
|
||||||
|
<inline>two</inline>
|
||||||
|
<text />
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const run = editor => {
|
||||||
|
Editor.moveNodes(editor, { at: [0, 1], to: [0, 3] })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const output = (
|
||||||
|
<editor>
|
||||||
|
<block>
|
||||||
|
<text />
|
||||||
|
<inline>two</inline>
|
||||||
|
<text />
|
||||||
|
<inline>
|
||||||
|
<cursor />
|
||||||
|
one
|
||||||
|
</inline>
|
||||||
|
<text />
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
@@ -0,0 +1,22 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block void>one</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const run = editor => {
|
||||||
|
Editor.removeNodes(editor, { at: [0, 0], voids: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const output = (
|
||||||
|
<editor>
|
||||||
|
<block void>
|
||||||
|
<text />
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
@@ -0,0 +1,30 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block>
|
||||||
|
<text />
|
||||||
|
<inline void>one</inline>
|
||||||
|
<text />
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const run = editor => {
|
||||||
|
Editor.removeNodes(editor, { at: [0, 1, 0], voids: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const output = (
|
||||||
|
<editor>
|
||||||
|
<block>
|
||||||
|
<text />
|
||||||
|
<inline void>
|
||||||
|
<text />
|
||||||
|
</inline>
|
||||||
|
<text />
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
22
packages/slate/test/transforms/setNodes/voids-true/block.js
Normal file
22
packages/slate/test/transforms/setNodes/voids-true/block.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block void>word</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const run = editor => {
|
||||||
|
Editor.setNodes(editor, { key: true }, { at: [0, 0], voids: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const output = (
|
||||||
|
<editor>
|
||||||
|
<block void>
|
||||||
|
<text key>word</text>
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
28
packages/slate/test/transforms/setNodes/voids-true/inline.js
Normal file
28
packages/slate/test/transforms/setNodes/voids-true/inline.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const run = editor => {
|
||||||
|
Editor.setNodes(editor, { key: 'a' }, { at: [0, 1] })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block>
|
||||||
|
<text />
|
||||||
|
<inline>word</inline>
|
||||||
|
<text />
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const output = (
|
||||||
|
<editor>
|
||||||
|
<block>
|
||||||
|
<text />
|
||||||
|
<inline key="a">word</inline>
|
||||||
|
<text />
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
@@ -0,0 +1,28 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const run = editor => {
|
||||||
|
Editor.splitNodes(editor, { at: [0, 1], voids: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block void>
|
||||||
|
<block>one</block>
|
||||||
|
<block>two</block>
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const output = (
|
||||||
|
<editor>
|
||||||
|
<block void>
|
||||||
|
<block>one</block>
|
||||||
|
</block>
|
||||||
|
<block void>
|
||||||
|
<block>two</block>
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
@@ -0,0 +1,37 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const run = editor => {
|
||||||
|
Editor.splitNodes(editor, { at: [0, 1, 1], voids: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block>
|
||||||
|
<text />
|
||||||
|
<inline void>
|
||||||
|
<text>one</text>
|
||||||
|
<text>two</text>
|
||||||
|
</inline>
|
||||||
|
<text />
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const output = (
|
||||||
|
<editor>
|
||||||
|
<block>
|
||||||
|
<text />
|
||||||
|
<inline void>
|
||||||
|
<text>one</text>
|
||||||
|
</inline>
|
||||||
|
<text />
|
||||||
|
<inline void>
|
||||||
|
<text>two</text>
|
||||||
|
</inline>
|
||||||
|
<text />
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
@@ -0,0 +1,22 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const run = editor => {
|
||||||
|
Editor.unwrapNodes(editor, { at: [0], voids: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block void>
|
||||||
|
<block>word</block>
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const output = (
|
||||||
|
<editor>
|
||||||
|
<block>word</block>
|
||||||
|
</editor>
|
||||||
|
)
|
28
packages/slate/test/transforms/wrapNodes/path/block.js
Normal file
28
packages/slate/test/transforms/wrapNodes/path/block.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const run = editor => {
|
||||||
|
Editor.wrapNodes(editor, <block a />, { at: [0] })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block>
|
||||||
|
<cursor />
|
||||||
|
word
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const output = (
|
||||||
|
<editor>
|
||||||
|
<block a>
|
||||||
|
<block>
|
||||||
|
<cursor />
|
||||||
|
word
|
||||||
|
</block>
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
22
packages/slate/test/transforms/wrapNodes/voids-true/block.js
Normal file
22
packages/slate/test/transforms/wrapNodes/voids-true/block.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/** @jsx jsx */
|
||||||
|
|
||||||
|
import { Editor } from 'slate'
|
||||||
|
import { jsx } from '../../..'
|
||||||
|
|
||||||
|
export const run = editor => {
|
||||||
|
Editor.wrapNodes(editor, <block a />, { at: [0, 0], voids: true })
|
||||||
|
}
|
||||||
|
|
||||||
|
export const input = (
|
||||||
|
<editor>
|
||||||
|
<block void>word</block>
|
||||||
|
</editor>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const output = (
|
||||||
|
<editor>
|
||||||
|
<block void>
|
||||||
|
<block a>word</block>
|
||||||
|
</block>
|
||||||
|
</editor>
|
||||||
|
)
|
Reference in New Issue
Block a user