diff --git a/packages/slate/src/create-editor.ts b/packages/slate/src/create-editor.ts index df1a8e4ff..6075bae0f 100755 --- a/packages/slate/src/create-editor.ts +++ b/packages/slate/src/create-editor.ts @@ -145,7 +145,7 @@ export const createEditor = (): Editor => { // Ensure that block and inline nodes have at least one text child. if (Element.isElement(node) && node.children.length === 0) { const child = { text: '' } - Editor.insertNodes(editor, child, { at: path.concat(0) }) + Editor.insertNodes(editor, child, { at: path.concat(0), voids: true }) return } @@ -175,43 +175,42 @@ export const createEditor = (): Editor => { // other inline nodes, or parent blocks that only contain inlines and // text. if (isInlineOrText !== shouldHaveInlines) { - Editor.removeNodes(editor, { at: path.concat(n) }) + Editor.removeNodes(editor, { at: path.concat(n), voids: true }) n-- - continue - } - - if (Element.isElement(child)) { + } else if (Element.isElement(child)) { // Ensure that inline nodes are surrounded by text nodes. if (editor.isInline(child)) { if (prev == null || !Text.isText(prev)) { const newChild = { text: '' } - Editor.insertNodes(editor, newChild, { at: path.concat(n) }) + Editor.insertNodes(editor, newChild, { + at: path.concat(n), + voids: true, + }) n++ - continue - } - - if (isLast) { + } else if (isLast) { const newChild = { text: '' } - Editor.insertNodes(editor, newChild, { at: path.concat(n + 1) }) + Editor.insertNodes(editor, newChild, { + at: path.concat(n + 1), + voids: true, + }) n++ - continue } } } else { // Merge adjacent text nodes that are empty or match. if (prev != null && Text.isText(prev)) { if (Text.equals(child, prev, { loose: true })) { - Editor.mergeNodes(editor, { at: path.concat(n) }) + Editor.mergeNodes(editor, { at: path.concat(n), voids: true }) n-- - continue } else if (prev.text === '') { - Editor.removeNodes(editor, { at: path.concat(n - 1) }) + Editor.removeNodes(editor, { + at: path.concat(n - 1), + voids: true, + }) n-- - continue } else if (isLast && child.text === '') { - Editor.removeNodes(editor, { at: path.concat(n) }) + Editor.removeNodes(editor, { at: path.concat(n), voids: true }) n-- - continue } } } diff --git a/packages/slate/src/interfaces/editor/queries/location.ts b/packages/slate/src/interfaces/editor/queries/location.ts index 8735bfbed..fcc3e2b95 100644 --- a/packages/slate/src/interfaces/editor/queries/location.ts +++ b/packages/slate/src/interfaces/editor/queries/location.ts @@ -137,9 +137,10 @@ export const LocationQueries = { match?: NodeMatch mode?: 'all' | 'highest' reverse?: boolean + voids?: boolean } = {} ): Iterable { - for (const [node, path] of this.nodes(editor, options)) { + for (const [node, path] of Editor.nodes(editor, options)) { if (Element.isElement(node)) { yield [node, path] } @@ -239,9 +240,10 @@ export const LocationQueries = { options: { at?: Location reverse?: boolean + voids?: boolean } = {} ): Iterable { - const { at = editor.selection, reverse = false } = options + const { at = editor.selection, reverse = false, voids = false } = options if (!at) { return @@ -253,7 +255,7 @@ export const LocationQueries = { for (const [n, p] of Node.levels(editor, path)) { levels.push([n, p]) - if (Element.isElement(n) && editor.isVoid(n)) { + if (!voids && Element.isElement(n) && editor.isVoid(n)) { break } } @@ -269,10 +271,18 @@ export const LocationQueries = { * 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) - 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)) { return entry } @@ -330,23 +340,21 @@ export const LocationQueries = { * 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 [, to] = Editor.last(editor, []) const span: Span = [from, to] - let i = 0 - - for (const entry of Editor.nodes(editor, { - at: span, - match, - mode: 'highest', - })) { - if (i === 1) { - return entry - } - - i++ - } + const [, next] = Editor.nodes(editor, { at: span, match, mode, voids }) + return next }, /** @@ -377,6 +385,7 @@ export const LocationQueries = { match?: NodeMatch mode?: 'all' | 'highest' reverse?: boolean + voids?: boolean } = {} ): Iterable { const { @@ -384,6 +393,7 @@ export const LocationQueries = { match, mode = 'all', reverse = false, + voids = false, } = options if (!at) { @@ -407,20 +417,19 @@ export const LocationQueries = { reverse, from, to, - pass: ([n]) => Element.isElement(n) && editor.isVoid(n), + pass: ([n]) => (voids ? false : Element.isElement(n) && editor.isVoid(n)), }) let prev: NodeEntry | undefined for (const entry of iterable) { - if (match != null) { - if (mode === 'highest' && prev) { - const [, prevPath] = prev - const [, path] = entry - - if (Path.compare(path, prevPath) === 0) { - continue - } + if (match) { + if ( + mode === 'highest' && + prev && + Path.compare(entry[1], prev[1]) === 0 + ) { + continue } if (!Editor.isMatch(editor, entry, match)) { @@ -669,25 +678,25 @@ export const LocationQueries = { previous( editor: Editor, at: Location, - match: NodeMatch + match: NodeMatch, + options: { + mode?: 'all' | 'highest' + voids?: boolean + } = {} ): NodeEntry | undefined { + const { mode = 'highest', voids = false } = options const [, from] = Editor.first(editor, at) const [, to] = Editor.first(editor, []) const span: Span = [from, to] - let i = 0 - - for (const entry of Editor.nodes(editor, { - match, - at: span, + const [, previous] = Editor.nodes(editor, { reverse: true, - mode: 'highest', - })) { - if (i === 1) { - return entry - } + at: span, + match, + mode, + voids, + }) - i++ - } + return previous }, /** @@ -752,9 +761,10 @@ export const LocationQueries = { match?: NodeMatch mode?: 'all' | 'highest' reverse?: boolean + voids?: boolean } = {} ): Iterable { - for (const [node, path] of this.nodes(editor, options)) { + for (const [node, path] of Editor.nodes(editor, options)) { if (Text.isText(node)) { yield [node, path] } diff --git a/packages/slate/src/interfaces/editor/queries/range.ts b/packages/slate/src/interfaces/editor/queries/range.ts index 92361483f..63e9047ff 100644 --- a/packages/slate/src/interfaces/editor/queries/range.ts +++ b/packages/slate/src/interfaces/editor/queries/range.ts @@ -5,7 +5,14 @@ export const RangeQueries = { * 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) // 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, { at: before, reverse: true, + voids, })) { if (skip) { skip = false diff --git a/packages/slate/src/interfaces/editor/transforms/node.ts b/packages/slate/src/interfaces/editor/transforms/node.ts index f16245121..d70a9388d 100644 --- a/packages/slate/src/interfaces/editor/transforms/node.ts +++ b/packages/slate/src/interfaces/editor/transforms/node.ts @@ -23,11 +23,12 @@ export const NodeTransforms = { at?: Location match?: NodeMatch hanging?: boolean + voids?: boolean } = {} ) { Editor.withoutNormalizing(editor, () => { const { selection } = editor - const { hanging = false } = options + const { hanging = false, voids = false } = options let { at, match } = options let select = false @@ -41,19 +42,6 @@ export const NodeTransforms = { 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 // no selection, insert at the end of the document since that is such a // common use case when inserting from a non-selected state. @@ -78,6 +66,16 @@ export const NodeTransforms = { } 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) if (atMatch) { @@ -95,7 +93,7 @@ export const NodeTransforms = { const parentPath = Path.parent(at) let index = at[at.length - 1] - if (Editor.match(editor, parentPath, 'void')) { + if (!voids && Editor.match(editor, parentPath, 'void')) { return } @@ -125,26 +123,23 @@ export const NodeTransforms = { options: { at?: Location match?: NodeMatch + mode?: 'all' | 'highest' + voids?: boolean } = {} ) { Editor.withoutNormalizing(editor, () => { - const { at = editor.selection } = options + const { at = editor.selection, mode = 'highest', voids = false } = options let { match } = options if (match == null) { - if (Path.isPath(at)) { - const path = at - match = ([, p]) => Path.equals(p, path) - } else { - match = 'block' - } + match = Path.isPath(at) ? matchPath(editor, at) : 'block' } if (!at) { 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)) for (const pathRef of pathRefs) { @@ -161,15 +156,19 @@ export const NodeTransforms = { const { length } = parent.children if (length === 1) { - Editor.moveNodes(editor, { at: path, to: Path.next(parentPath) }) - Editor.removeNodes(editor, { at: parentPath }) + const toPath = Path.next(parentPath) + Editor.moveNodes(editor, { at: path, to: toPath, voids }) + Editor.removeNodes(editor, { at: parentPath, voids }) } else if (index === 0) { - Editor.moveNodes(editor, { at: path, to: parentPath }) + Editor.moveNodes(editor, { at: path, to: parentPath, voids }) } 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 { - Editor.splitNodes(editor, { at: Path.next(path) }) - Editor.moveNodes(editor, { at: path, to: Path.next(parentPath) }) + const splitPath = Path.next(path) + 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 match?: NodeMatch hanging?: boolean + voids?: boolean } = {} ) { Editor.withoutNormalizing(editor, () => { let { match, at = editor.selection } = options - const { hanging = false } = options - - if (match == null) { - if (Path.isPath(at)) { - const path = at - match = ([, p]) => Path.equals(p, path) - } else { - match = 'block' - } - } + const { hanging = false, voids = false } = options if (!at) { return } + if (match == null) { + match = Path.isPath(at) ? matchPath(editor, at) : 'block' + } + if (!hanging && Range.isRange(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) { return @@ -241,7 +236,7 @@ export const NodeTransforms = { prevMatch = 'inline' } - const prev = Editor.previous(editor, at, prevMatch) + const prev = Editor.previous(editor, at, prevMatch, { voids }) if (!prev) { return @@ -288,13 +283,13 @@ export const NodeTransforms = { // If the node isn't already the next sibling of the previous node, move // it so that it is before merging. 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, // we remove it from the tree. 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 @@ -305,7 +300,7 @@ export const NodeTransforms = { (Element.isElement(prevNode) && Editor.isEmpty(editor, prevNode)) || (Text.isText(prevNode) && prevNode.text === '') ) { - Editor.removeNodes(editor, { at: prevPath }) + Editor.removeNodes(editor, { at: prevPath, voids }) } else { editor.apply({ type: 'merge_node', @@ -331,28 +326,30 @@ export const NodeTransforms = { options: { at?: Location match?: NodeMatch + mode?: 'all' | 'highest' to: Path + voids?: boolean } ) { Editor.withoutNormalizing(editor, () => { - const { to, at = editor.selection } = options + const { + to, + at = editor.selection, + mode = 'highest', + voids = false, + } = 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) { return } + if (match == null) { + match = Path.isPath(at) ? matchPath(editor, at) : 'block' + } + 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)) for (const pathRef of pathRefs) { @@ -377,37 +374,41 @@ export const NodeTransforms = { options: { at?: Location match?: NodeMatch + mode?: 'all' | 'highest' hanging?: boolean + voids?: boolean } = {} ) { Editor.withoutNormalizing(editor, () => { - let { match, at = editor.selection } = options - const { hanging = false } = options - - if (match == null) { - if (Path.isPath(at)) { - const path = at - match = ([, p]) => Path.equals(p, path) - } else { - match = 'block' - } - } + const { hanging = false, voids = false } = options + let { at = editor.selection, mode, match } = options if (!at) { return } + if (match == null) { + match = Path.isPath(at) ? matchPath(editor, at) : 'block' + } + + if (mode == null || mode === 'all') { + mode = 'highest' + } + if (!hanging && Range.isRange(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)) for (const pathRef of pathRefs) { 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' hanging?: boolean split?: boolean + voids?: boolean } = {} ) { Editor.withoutNormalizing(editor, () => { let { match, at = editor.selection } = options - const { hanging = false, mode = 'highest', split = false } = options - - if (match == null) { - if (Path.isPath(at)) { - const path = at - match = ([, p]) => Path.equals(p, path) - } else { - match = 'block' - } - } + const { + hanging = false, + mode = 'highest', + split = false, + voids = false, + } = options if (!at) { return } + if (match == null) { + match = Path.isPath(at) ? matchPath(editor, at) : 'block' + } + if (!hanging && Range.isRange(at)) { at = Editor.unhangRange(editor, at) } @@ -451,8 +453,8 @@ export const NodeTransforms = { if (split && Range.isRange(at)) { const rangeRef = Editor.rangeRef(editor, at, { affinity: 'inward' }) const [start, end] = Range.edges(at) - Editor.splitNodes(editor, { at: end, match }) - Editor.splitNodes(editor, { at: start, match }) + Editor.splitNodes(editor, { at: end, match, voids }) + Editor.splitNodes(editor, { at: start, match, voids }) at = rangeRef.unref()! 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 = {} const newProperties: Partial = {} @@ -503,10 +510,17 @@ export const NodeTransforms = { match?: NodeMatch always?: boolean height?: number + voids?: boolean } = {} ) { 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) { match = 'block' @@ -534,7 +548,7 @@ export const NodeTransforms = { const beforeRef = Editor.pointRef(editor, at, { affinity: 'backward', }) - const highest = Editor.match(editor, at, match) + const highest = Editor.match(editor, at, match, { voids }) if (!highest) { return @@ -543,7 +557,7 @@ export const NodeTransforms = { const voidMatch = Editor.match(editor, at, 'void') const nudge = 0 - if (voidMatch) { + if (!voids && voidMatch) { const [voidNode, voidPath] = voidMatch if (Element.isElement(voidNode) && editor.isInline(voidNode)) { @@ -552,7 +566,7 @@ export const NodeTransforms = { if (!after) { const text = { text: '' } const afterPath = Path.next(voidPath) - Editor.insertNodes(editor, text, { at: afterPath }) + Editor.insertNodes(editor, text, { at: afterPath, voids }) after = Editor.point(editor, afterPath)! } @@ -575,13 +589,14 @@ export const NodeTransforms = { for (const [node, path] of Editor.levels(editor, { at: lowestPath, reverse: true, + voids, })) { let split = false if ( path.length < highestPath.length || path.length === 0 || - (Element.isElement(node) && editor.isVoid(node)) + (!voids && Element.isElement(node) && editor.isVoid(node)) ) { break } @@ -625,27 +640,29 @@ export const NodeTransforms = { options: { at?: Location match?: NodeMatch + mode?: 'all' | 'highest' split?: boolean + voids?: boolean } ) { Editor.withoutNormalizing(editor, () => { - const { at = editor.selection, split = false } = options + const { + at = editor.selection, + mode = 'highest', + split = false, + voids = false, + } = 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) { 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)) for (const pathRef of pathRefs) { @@ -660,6 +677,7 @@ export const NodeTransforms = { Editor.liftNodes(editor, { at: range, match: ([, p]) => p.length === depth, + voids, }) } }) @@ -676,11 +694,13 @@ export const NodeTransforms = { options: { at?: Location match?: NodeMatch + mode?: 'all' | 'highest' split?: boolean + voids?: boolean } = {} ) { Editor.withoutNormalizing(editor, () => { - const { split = false } = options + const { mode = 'highest', split = false, voids = false } = options let { match, at = editor.selection } = options if (!at) { @@ -689,8 +709,7 @@ export const NodeTransforms = { if (match == null) { if (Path.isPath(at)) { - const path = at - match = ([, p]) => Path.equals(p, path) + match = matchPath(editor, at) } else if (editor.isInline(element)) { match = ['inline', 'text'] } else { @@ -703,8 +722,8 @@ export const NodeTransforms = { const rangeRef = Editor.rangeRef(editor, at, { affinity: 'inward', }) - Editor.splitNodes(editor, { at: end, match }) - Editor.splitNodes(editor, { at: start, match }) + Editor.splitNodes(editor, { at: end, match, voids }) + Editor.splitNodes(editor, { at: start, match, voids }) at = rangeRef.unref()! if (options.at == null) { @@ -712,16 +731,14 @@ export const NodeTransforms = { } } - const roots: NodeEntry[] = editor.isInline(element) - ? Array.from( - Editor.nodes(editor, { - ...options, - at, - match: 'block', - mode: 'highest', - }) - ) - : [[editor, []]] + const roots = Array.from( + Editor.nodes(editor, { + at, + match: editor.isInline(element) ? 'block' : 'editor', + mode: 'highest', + voids, + }) + ) for (const [, rootPath] of roots) { const a = Range.isRange(at) @@ -733,7 +750,7 @@ export const NodeTransforms = { } 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) { @@ -749,12 +766,13 @@ export const NodeTransforms = { const depth = commonPath.length + 1 const wrapperPath = Path.next(lastPath).slice(0, depth) const wrapper = { ...element, children: [] } - Editor.insertNodes(editor, wrapper, { at: wrapperPath }) + Editor.insertNodes(editor, wrapper, { at: wrapperPath, voids }) Editor.moveNodes(editor, { at: range, match: ([, p]) => p.length === depth, to: wrapperPath.concat(0), + voids, }) } } @@ -776,3 +794,11 @@ const deleteRange = (editor: Editor, range: Range): Point | null => { return pointRef.unref() } } + +const matchPath = ( + editor: Editor, + path: Path +): ((entry: NodeEntry) => boolean) => { + const [node] = Editor.node(editor, path) + return ([n]) => n === node +} diff --git a/packages/slate/src/interfaces/editor/transforms/text.ts b/packages/slate/src/interfaces/editor/transforms/text.ts index eb500ec30..1074b7007 100644 --- a/packages/slate/src/interfaces/editor/transforms/text.ts +++ b/packages/slate/src/interfaces/editor/transforms/text.ts @@ -22,10 +22,16 @@ export const TextTransforms = { unit?: 'character' | 'word' | 'line' | 'block' reverse?: boolean hanging?: boolean + voids?: boolean } = {} ) { 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 if (!at) { @@ -39,7 +45,7 @@ export const TextTransforms = { if (Point.isPoint(at)) { const furthestVoid = Editor.match(editor, at.path, 'void') - if (furthestVoid) { + if (!voids && furthestVoid) { const [, voidPath] = furthestVoid at = voidPath } else { @@ -53,7 +59,7 @@ export const TextTransforms = { } if (Path.isPath(at)) { - Editor.removeNodes(editor, { at }) + Editor.removeNodes(editor, { at, voids }) return } @@ -62,17 +68,17 @@ export const TextTransforms = { } if (!hanging) { - at = Editor.unhangRange(editor, at) + at = Editor.unhangRange(editor, at, { voids }) } let [start, end] = Range.edges(at) - const startBlock = Editor.match(editor, start.path, 'block') - const endBlock = Editor.match(editor, end.path, 'block') + const startBlock = Editor.match(editor, start.path, 'block', { voids }) + const endBlock = Editor.match(editor, end.path, 'block', { voids }) const isAcrossBlocks = startBlock && endBlock && !Path.equals(startBlock[1], endBlock[1]) const isSingleText = Path.equals(start.path, end.path) - const startVoid = Editor.match(editor, start.path, 'void') - const endVoid = Editor.match(editor, end.path, 'void') + const startVoid = voids ? null : Editor.match(editor, start.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 (startVoid) { @@ -99,9 +105,10 @@ export const TextTransforms = { // the start and end nodes. const matches = Editor.nodes(editor, { at, + voids, mode: 'highest', 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)), }) @@ -120,7 +127,7 @@ export const TextTransforms = { for (const pathRef of pathRefs) { const path = pathRef.unref()! - Editor.removeNodes(editor, { at: path }) + Editor.removeNodes(editor, { at: path, voids }) } if (!endVoid) { @@ -138,7 +145,11 @@ export const TextTransforms = { endRef.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() @@ -159,11 +170,12 @@ export const TextTransforms = { options: { at?: Location hanging?: boolean + voids?: boolean } = {} ) { Editor.withoutNormalizing(editor, () => { + const { hanging = false, voids = false } = options let { at = editor.selection } = options - const { hanging = false } = options if (!fragment.length) { return @@ -180,6 +192,11 @@ export const TextTransforms = { at = at.anchor } else { const [, end] = Range.edges(at) + + if (!voids && Editor.match(editor, end, 'void')) { + return + } + const pointRef = Editor.pointRef(editor, end) Editor.delete(editor, { at }) at = pointRef.unref()! @@ -188,13 +205,13 @@ export const TextTransforms = { at = Editor.start(editor, at) } - if (Editor.match(editor, at.path, 'void')) { + if (!voids && Editor.match(editor, at.path, 'void')) { return } // If the insert point is at the edge of an inline node, move it outside // 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) { 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 isBlockStart = Editor.isStart(editor, at, blockPath) const isBlockEnd = Editor.isEnd(editor, at, blockPath) @@ -217,9 +234,7 @@ export const TextTransforms = { const [, firstPath] = Node.first({ children: fragment }, []) const [, lastPath] = Node.last({ children: fragment }, []) - // TODO: convert into a proper `Nodes.matches` iterable const matches: NodeEntry[] = [] - const matcher = ([n, p]: NodeEntry) => { if ( 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 isInlineStart = Editor.isStart(editor, at, inlinePath) const isInlineEnd = Editor.isEnd(editor, at, inlinePath) @@ -289,6 +306,7 @@ export const TextTransforms = { Editor.splitNodes(editor, { at, match: hasBlocks ? 'block' : ['inline', 'text'], + voids, }) const startRef = Editor.pathRef( @@ -301,16 +319,19 @@ export const TextTransforms = { Editor.insertNodes(editor, starts, { at: startRef.current!, match: ['inline', 'text'], + voids, }) Editor.insertNodes(editor, middles, { at: middleRef.current!, match: 'block', + voids, }) Editor.insertNodes(editor, ends, { at: endRef.current!, match: ['inline', 'text'], + voids, }) if (!options.at) { @@ -343,9 +364,11 @@ export const TextTransforms = { text: string, options: { at?: Location + voids?: boolean } = {} ) { Editor.withoutNormalizing(editor, () => { + const { voids = false } = options let { at = editor.selection } = options if (!at) { @@ -360,13 +383,19 @@ export const TextTransforms = { if (Range.isCollapsed(at)) { at = at.anchor } else { - const pointRef = Editor.pointRef(editor, Range.end(at)) - Editor.delete(editor, { at }) + const end = Range.end(at) + + if (!voids && Editor.match(editor, end, 'void')) { + return + } + + const pointRef = Editor.pointRef(editor, end) + Editor.delete(editor, { at, voids }) at = pointRef.unref()! } } - if (Editor.match(editor, at.path, 'void')) { + if (!voids && Editor.match(editor, at.path, 'void')) { return } diff --git a/packages/slate/test/queries/nodes/voids-true/block.js b/packages/slate/test/queries/nodes/voids-true/block.js new file mode 100644 index 000000000..a6da5facf --- /dev/null +++ b/packages/slate/test/queries/nodes/voids-true/block.js @@ -0,0 +1,18 @@ +/** @jsx jsx */ + +import { Editor } from 'slate' +import { jsx } from '../../..' + +export const input = ( + + one + +) + +export const run = editor => { + return Array.from( + Editor.nodes(editor, { at: [], match: 'text', voids: true }) + ) +} + +export const output = [[one, [0, 0]]] diff --git a/packages/slate/test/queries/nodes/voids-true/inline.js b/packages/slate/test/queries/nodes/voids-true/inline.js new file mode 100644 index 000000000..b908db47c --- /dev/null +++ b/packages/slate/test/queries/nodes/voids-true/inline.js @@ -0,0 +1,24 @@ +/** @jsx jsx */ + +import { Editor } from 'slate' +import { jsx } from '../../..' + +export const input = ( + + + onetwothree + + +) + +export const run = editor => { + return Array.from( + Editor.nodes(editor, { at: [], match: 'text', voids: true }) + ) +} + +export const output = [ + [one, [0, 0]], + [two, [0, 1, 0]], + [three, [0, 2]], +] diff --git a/packages/slate/test/transforms/delete/voids/block-across-backward.js b/packages/slate/test/transforms/delete/voids-false/block-across-backward.js similarity index 100% rename from packages/slate/test/transforms/delete/voids/block-across-backward.js rename to packages/slate/test/transforms/delete/voids-false/block-across-backward.js diff --git a/packages/slate/test/transforms/delete/voids/block-after-reverse.js b/packages/slate/test/transforms/delete/voids-false/block-after-reverse.js similarity index 100% rename from packages/slate/test/transforms/delete/voids/block-after-reverse.js rename to packages/slate/test/transforms/delete/voids-false/block-after-reverse.js diff --git a/packages/slate/test/transforms/delete/voids/block-before.js b/packages/slate/test/transforms/delete/voids-false/block-before.js similarity index 100% rename from packages/slate/test/transforms/delete/voids/block-before.js rename to packages/slate/test/transforms/delete/voids-false/block-before.js diff --git a/packages/slate/test/transforms/delete/voids/block-both.js b/packages/slate/test/transforms/delete/voids-false/block-both.js similarity index 100% rename from packages/slate/test/transforms/delete/voids/block-both.js rename to packages/slate/test/transforms/delete/voids-false/block-both.js diff --git a/packages/slate/test/transforms/delete/voids/block-end.js b/packages/slate/test/transforms/delete/voids-false/block-end.js similarity index 100% rename from packages/slate/test/transforms/delete/voids/block-end.js rename to packages/slate/test/transforms/delete/voids-false/block-end.js diff --git a/packages/slate/test/transforms/delete/voids/block-hanging-from.js b/packages/slate/test/transforms/delete/voids-false/block-hanging-from.js similarity index 100% rename from packages/slate/test/transforms/delete/voids/block-hanging-from.js rename to packages/slate/test/transforms/delete/voids-false/block-hanging-from.js diff --git a/packages/slate/test/transforms/delete/voids/block-hanging-into.js b/packages/slate/test/transforms/delete/voids-false/block-hanging-into.js similarity index 100% rename from packages/slate/test/transforms/delete/voids/block-hanging-into.js rename to packages/slate/test/transforms/delete/voids-false/block-hanging-into.js diff --git a/packages/slate/test/transforms/delete/voids/block-only.js b/packages/slate/test/transforms/delete/voids-false/block-only.js similarity index 100% rename from packages/slate/test/transforms/delete/voids/block-only.js rename to packages/slate/test/transforms/delete/voids-false/block-only.js diff --git a/packages/slate/test/transforms/delete/voids/block-start-multiple.js b/packages/slate/test/transforms/delete/voids-false/block-start-multiple.js similarity index 100% rename from packages/slate/test/transforms/delete/voids/block-start-multiple.js rename to packages/slate/test/transforms/delete/voids-false/block-start-multiple.js diff --git a/packages/slate/test/transforms/delete/voids/block-start.js b/packages/slate/test/transforms/delete/voids-false/block-start.js similarity index 100% rename from packages/slate/test/transforms/delete/voids/block-start.js rename to packages/slate/test/transforms/delete/voids-false/block-start.js diff --git a/packages/slate/test/transforms/delete/voids/inline-after-reverse.js b/packages/slate/test/transforms/delete/voids-false/inline-after-reverse.js similarity index 100% rename from packages/slate/test/transforms/delete/voids/inline-after-reverse.js rename to packages/slate/test/transforms/delete/voids-false/inline-after-reverse.js diff --git a/packages/slate/test/transforms/delete/voids/inline-before.js b/packages/slate/test/transforms/delete/voids-false/inline-before.js similarity index 100% rename from packages/slate/test/transforms/delete/voids/inline-before.js rename to packages/slate/test/transforms/delete/voids-false/inline-before.js diff --git a/packages/slate/test/transforms/delete/voids/inline-into.js b/packages/slate/test/transforms/delete/voids-false/inline-into.js similarity index 100% rename from packages/slate/test/transforms/delete/voids/inline-into.js rename to packages/slate/test/transforms/delete/voids-false/inline-into.js diff --git a/packages/slate/test/transforms/delete/voids/inline-over.js b/packages/slate/test/transforms/delete/voids-false/inline-over.js similarity index 100% rename from packages/slate/test/transforms/delete/voids/inline-over.js rename to packages/slate/test/transforms/delete/voids-false/inline-over.js diff --git a/packages/slate/test/transforms/delete/voids/inline-start-across.js b/packages/slate/test/transforms/delete/voids-false/inline-start-across.js similarity index 100% rename from packages/slate/test/transforms/delete/voids/inline-start-across.js rename to packages/slate/test/transforms/delete/voids-false/inline-start-across.js diff --git a/packages/slate/test/transforms/delete/voids/inline-start.js b/packages/slate/test/transforms/delete/voids-false/inline-start.js similarity index 100% rename from packages/slate/test/transforms/delete/voids/inline-start.js rename to packages/slate/test/transforms/delete/voids-false/inline-start.js diff --git a/packages/slate/test/transforms/delete/voids-true/across-blocks.js b/packages/slate/test/transforms/delete/voids-true/across-blocks.js new file mode 100644 index 000000000..cfce0d6d7 --- /dev/null +++ b/packages/slate/test/transforms/delete/voids-true/across-blocks.js @@ -0,0 +1,35 @@ +/** @jsx jsx */ + +import { Editor } from 'slate' +import { jsx } from '../../..' + +export const input = ( + + + + on + e + + + + + t + wo + + + +) + +export const run = editor => { + Editor.delete(editor, { voids: true }) +} + +export const output = ( + + + on + + wo + + +) diff --git a/packages/slate/test/transforms/delete/voids-true/path.js b/packages/slate/test/transforms/delete/voids-true/path.js new file mode 100644 index 000000000..3d811c652 --- /dev/null +++ b/packages/slate/test/transforms/delete/voids-true/path.js @@ -0,0 +1,24 @@ +/** @jsx jsx */ + +import { Editor } from 'slate' +import { jsx } from '../../..' + +export const input = ( + + + one + + +) + +export const run = editor => { + Editor.delete(editor, { at: [0, 0], voids: true }) +} + +export const output = ( + + + + + +) diff --git a/packages/slate/test/transforms/insertFragment/voids-false/block.js b/packages/slate/test/transforms/insertFragment/voids-false/block.js new file mode 100644 index 000000000..4c22ede63 --- /dev/null +++ b/packages/slate/test/transforms/insertFragment/voids-false/block.js @@ -0,0 +1,28 @@ +/** @jsx jsx */ + +import { Editor } from 'slate' +import { jsx } from '../../..' + +export const run = editor => { + Editor.insertFragment(editor, fragment) +} + +export const input = ( + + + wo + + rd + + +) + +export const output = ( + + + wo + + rd + + +) diff --git a/packages/slate/test/transforms/insertFragment/voids-false/inline.js b/packages/slate/test/transforms/insertFragment/voids-false/inline.js new file mode 100644 index 000000000..dcf4d56c8 --- /dev/null +++ b/packages/slate/test/transforms/insertFragment/voids-false/inline.js @@ -0,0 +1,37 @@ +/** @jsx jsx */ + +import { Editor } from 'slate' +import { jsx } from '../../..' + +export const run = editor => { + Editor.insertFragment(editor, fragment) +} + +export const input = ( + + + + + wo + + rd + + + + +) + +// TODO: argument to made that fragment should go into the inline +export const output = ( + + + + + wo + + rd + + + + +) diff --git a/packages/slate/test/transforms/insertFragment/voids-true/block.js b/packages/slate/test/transforms/insertFragment/voids-true/block.js new file mode 100644 index 000000000..e030fe7c9 --- /dev/null +++ b/packages/slate/test/transforms/insertFragment/voids-true/block.js @@ -0,0 +1,28 @@ +/** @jsx jsx */ + +import { Editor } from 'slate' +import { jsx } from '../../..' + +export const run = editor => { + Editor.insertFragment(editor, fragment, { voids: true }) +} + +export const input = ( + + + wo + + rd + + +) + +export const output = ( + + + wofragment + + rd + + +) diff --git a/packages/slate/test/transforms/insertFragment/voids-true/inline.js b/packages/slate/test/transforms/insertFragment/voids-true/inline.js new file mode 100644 index 000000000..2177ce5b8 --- /dev/null +++ b/packages/slate/test/transforms/insertFragment/voids-true/inline.js @@ -0,0 +1,36 @@ +/** @jsx jsx */ + +import { Editor } from 'slate' +import { jsx } from '../../..' + +export const run = editor => { + Editor.insertFragment(editor, fragment, { voids: true }) +} + +export const input = ( + + + + + wo + + rd + + + + +) + +// TODO: argument to made that fragment should go into the inline +export const output = ( + + + + wo + fragment + + rd + + + +) diff --git a/packages/slate/test/transforms/insertNodes/voids-true/block.js b/packages/slate/test/transforms/insertNodes/voids-true/block.js new file mode 100644 index 000000000..d2840ea11 --- /dev/null +++ b/packages/slate/test/transforms/insertNodes/voids-true/block.js @@ -0,0 +1,29 @@ +/** @jsx jsx */ + +import { Editor } from 'slate' +import { jsx } from '../../..' + +export const input = ( + + + one + + + +) + +export const run = editor => { + Editor.insertNodes(editor, two, { + at: [0, 1], + voids: true, + }) +} + +export const output = ( + + + onetwo + + + +) diff --git a/packages/slate/test/transforms/insertNodes/voids-true/inline.js b/packages/slate/test/transforms/insertNodes/voids-true/inline.js new file mode 100644 index 000000000..3a9a922dc --- /dev/null +++ b/packages/slate/test/transforms/insertNodes/voids-true/inline.js @@ -0,0 +1,37 @@ +/** @jsx jsx */ + +import { Editor } from 'slate' +import { jsx } from '../../..' + +export const input = ( + + + one + + two + + + three + + +) + +export const run = editor => { + Editor.insertNodes(editor, four, { + at: [0, 1, 1], + voids: true, + }) +} + +export const output = ( + + + one + + twofour + + + three + + +) diff --git a/packages/slate/test/transforms/insertText/voids-false/block.js b/packages/slate/test/transforms/insertText/voids-false/block.js new file mode 100644 index 000000000..e552e45d1 --- /dev/null +++ b/packages/slate/test/transforms/insertText/voids-false/block.js @@ -0,0 +1,20 @@ +/** @jsx jsx */ + +import { Editor } from 'slate' +import { jsx } from '../../..' + +export const input = ( + + word + +) + +export const run = editor => { + Editor.insertText(editor, 'x', { at: [0] }) +} + +export const output = ( + + word + +) diff --git a/packages/slate/test/transforms/insertText/voids-false/text.js b/packages/slate/test/transforms/insertText/voids-false/text.js new file mode 100644 index 000000000..4dd29821b --- /dev/null +++ b/packages/slate/test/transforms/insertText/voids-false/text.js @@ -0,0 +1,20 @@ +/** @jsx jsx */ + +import { Editor } from 'slate' +import { jsx } from '../../..' + +export const input = ( + + word + +) + +export const run = editor => { + Editor.insertText(editor, 'x', { at: [0, 0] }) +} + +export const output = ( + + word + +) diff --git a/packages/slate/test/transforms/insertText/voids-true/block.js b/packages/slate/test/transforms/insertText/voids-true/block.js new file mode 100644 index 000000000..05a5763ef --- /dev/null +++ b/packages/slate/test/transforms/insertText/voids-true/block.js @@ -0,0 +1,20 @@ +/** @jsx jsx */ + +import { Editor } from 'slate' +import { jsx } from '../../..' + +export const input = ( + + word + +) + +export const run = editor => { + Editor.insertText(editor, 'x', { at: [0], voids: true }) +} + +export const output = ( + + x + +) diff --git a/packages/slate/test/transforms/insertText/voids-true/text.js b/packages/slate/test/transforms/insertText/voids-true/text.js new file mode 100644 index 000000000..9309c56c7 --- /dev/null +++ b/packages/slate/test/transforms/insertText/voids-true/text.js @@ -0,0 +1,20 @@ +/** @jsx jsx */ + +import { Editor } from 'slate' +import { jsx } from '../../..' + +export const input = ( + + word + +) + +export const run = editor => { + Editor.insertText(editor, 'x', { at: [0, 0], voids: true }) +} + +export const output = ( + + x + +) diff --git a/packages/slate/test/transforms/liftNodes/voids-true/block.js b/packages/slate/test/transforms/liftNodes/voids-true/block.js new file mode 100644 index 000000000..d4407c2b3 --- /dev/null +++ b/packages/slate/test/transforms/liftNodes/voids-true/block.js @@ -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 = ( + + + word + + +) + +export const output = ( + + word + +) diff --git a/packages/slate/test/transforms/mergeNodes/voids-true/block.js b/packages/slate/test/transforms/mergeNodes/voids-true/block.js new file mode 100644 index 000000000..49710ceac --- /dev/null +++ b/packages/slate/test/transforms/mergeNodes/voids-true/block.js @@ -0,0 +1,23 @@ +/** @jsx jsx */ + +import { Editor } from 'slate' +import { jsx } from '../../..' + +export const input = ( + + + one + two + + +) + +export const run = editor => { + Editor.mergeNodes(editor, { at: [0, 1], voids: true }) +} + +export const output = ( + + onetwo + +) diff --git a/packages/slate/test/transforms/moveNodes/voids-true/block.js b/packages/slate/test/transforms/moveNodes/voids-true/block.js new file mode 100644 index 000000000..7204de477 --- /dev/null +++ b/packages/slate/test/transforms/moveNodes/voids-true/block.js @@ -0,0 +1,28 @@ +/** @jsx jsx */ + +import { Editor } from 'slate' +import { jsx } from '../../..' + +export const input = ( + + one + two + +) + +export const run = editor => { + Editor.moveNodes(editor, { + at: [0, 0], + to: [1, 0], + voids: true, + }) +} + +export const output = ( + + + + + onetwo + +) diff --git a/packages/slate/test/transforms/moveNodes/voids-true/inline.js b/packages/slate/test/transforms/moveNodes/voids-true/inline.js new file mode 100644 index 000000000..5ef8fee3e --- /dev/null +++ b/packages/slate/test/transforms/moveNodes/voids-true/inline.js @@ -0,0 +1,38 @@ +/** @jsx jsx */ + +import { Editor } from 'slate' +import { jsx } from '../../..' + +export const input = ( + + + + + + one + + + two + + + +) + +export const run = editor => { + Editor.moveNodes(editor, { at: [0, 1], to: [0, 3] }) +} + +export const output = ( + + + + two + + + + one + + + + +) diff --git a/packages/slate/test/transforms/removeNodes/voids-true/block.js b/packages/slate/test/transforms/removeNodes/voids-true/block.js new file mode 100644 index 000000000..52b3e3fb6 --- /dev/null +++ b/packages/slate/test/transforms/removeNodes/voids-true/block.js @@ -0,0 +1,22 @@ +/** @jsx jsx */ + +import { Editor } from 'slate' +import { jsx } from '../../..' + +export const input = ( + + one + +) + +export const run = editor => { + Editor.removeNodes(editor, { at: [0, 0], voids: true }) +} + +export const output = ( + + + + + +) diff --git a/packages/slate/test/transforms/removeNodes/voids-true/inline.js b/packages/slate/test/transforms/removeNodes/voids-true/inline.js new file mode 100644 index 000000000..7f8117c0b --- /dev/null +++ b/packages/slate/test/transforms/removeNodes/voids-true/inline.js @@ -0,0 +1,30 @@ +/** @jsx jsx */ + +import { Editor } from 'slate' +import { jsx } from '../../..' + +export const input = ( + + + + one + + + +) + +export const run = editor => { + Editor.removeNodes(editor, { at: [0, 1, 0], voids: true }) +} + +export const output = ( + + + + + + + + + +) diff --git a/packages/slate/test/transforms/setNodes/voids-true/block.js b/packages/slate/test/transforms/setNodes/voids-true/block.js new file mode 100644 index 000000000..2d2ea6b2d --- /dev/null +++ b/packages/slate/test/transforms/setNodes/voids-true/block.js @@ -0,0 +1,22 @@ +/** @jsx jsx */ + +import { Editor } from 'slate' +import { jsx } from '../../..' + +export const input = ( + + word + +) + +export const run = editor => { + Editor.setNodes(editor, { key: true }, { at: [0, 0], voids: true }) +} + +export const output = ( + + + word + + +) diff --git a/packages/slate/test/transforms/setNodes/voids-true/inline.js b/packages/slate/test/transforms/setNodes/voids-true/inline.js new file mode 100644 index 000000000..eb7fd1cb0 --- /dev/null +++ b/packages/slate/test/transforms/setNodes/voids-true/inline.js @@ -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 = ( + + + + word + + + +) + +export const output = ( + + + + word + + + +) diff --git a/packages/slate/test/transforms/splitNodes/voids-true/block.js b/packages/slate/test/transforms/splitNodes/voids-true/block.js new file mode 100644 index 000000000..8087f982b --- /dev/null +++ b/packages/slate/test/transforms/splitNodes/voids-true/block.js @@ -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 = ( + + + one + two + + +) + +export const output = ( + + + one + + + two + + +) diff --git a/packages/slate/test/transforms/splitNodes/voids-true/inline.js b/packages/slate/test/transforms/splitNodes/voids-true/inline.js new file mode 100644 index 000000000..d5220cfdb --- /dev/null +++ b/packages/slate/test/transforms/splitNodes/voids-true/inline.js @@ -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 = ( + + + + + one + two + + + + +) + +export const output = ( + + + + + one + + + + two + + + + +) diff --git a/packages/slate/test/transforms/unwrapNodes/voids-true/block.js b/packages/slate/test/transforms/unwrapNodes/voids-true/block.js new file mode 100644 index 000000000..1a765c89e --- /dev/null +++ b/packages/slate/test/transforms/unwrapNodes/voids-true/block.js @@ -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 = ( + + + word + + +) + +export const output = ( + + word + +) diff --git a/packages/slate/test/transforms/wrapNodes/path/block.js b/packages/slate/test/transforms/wrapNodes/path/block.js new file mode 100644 index 000000000..3ee903e9b --- /dev/null +++ b/packages/slate/test/transforms/wrapNodes/path/block.js @@ -0,0 +1,28 @@ +/** @jsx jsx */ + +import { Editor } from 'slate' +import { jsx } from '../../..' + +export const run = editor => { + Editor.wrapNodes(editor, , { at: [0] }) +} + +export const input = ( + + + + word + + +) + +export const output = ( + + + + + word + + + +) diff --git a/packages/slate/test/transforms/wrapNodes/voids-true/block.js b/packages/slate/test/transforms/wrapNodes/voids-true/block.js new file mode 100644 index 000000000..f12072c3e --- /dev/null +++ b/packages/slate/test/transforms/wrapNodes/voids-true/block.js @@ -0,0 +1,22 @@ +/** @jsx jsx */ + +import { Editor } from 'slate' +import { jsx } from '../../..' + +export const run = editor => { + Editor.wrapNodes(editor, , { at: [0, 0], voids: true }) +} + +export const input = ( + + word + +) + +export const output = ( + + + word + + +)