1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-17 20:51:20 +02:00

moved getLeaves from react to slate core package and added some basic tests (#3358)

This commit is contained in:
Johan Sörlin
2019-12-19 17:51:44 +01:00
committed by Ian Storm Taylor
parent e54b07eba8
commit 5418e260d4
6 changed files with 221 additions and 75 deletions

View File

@@ -25,7 +25,7 @@ const Text = (props: {
const { decorations, isLast, parent, renderLeaf, text } = props const { decorations, isLast, parent, renderLeaf, text } = props
const editor = useEditor() const editor = useEditor()
const ref = useRef<HTMLSpanElement>(null) const ref = useRef<HTMLSpanElement>(null)
const leaves = getLeaves(text, decorations) const leaves = SlateText.decorations(text, decorations)
const key = ReactEditor.findKey(editor, text) const key = ReactEditor.findKey(editor, text)
const children = [] const children = []
@@ -63,79 +63,6 @@ const Text = (props: {
) )
} }
/**
* Get the leaves for a text node given decorations.
*/
const getLeaves = (node: SlateText, decorations: Range[]): SlateText[] => {
let leaves: SlateText[] = [{ ...node }]
for (const dec of decorations) {
const { anchor, focus, ...rest } = dec
const [start, end] = Range.edges(dec)
const next = []
let o = 0
for (const leaf of leaves) {
const { length } = leaf.text
const offset = o
o += length
// If the range encompases the entire leaf, add the range.
if (start.offset <= offset && end.offset >= offset + length) {
Object.assign(leaf, rest)
next.push(leaf)
continue
}
// If the range starts after the leaf, or ends before it, continue.
if (
start.offset > offset + length ||
end.offset < offset ||
(end.offset === offset && offset !== 0)
) {
next.push(leaf)
continue
}
// Otherwise we need to split the leaf, at the start, end, or both,
// and add the range to the middle intersecting section. Do the end
// split first since we don't need to update the offset that way.
let middle = leaf
let before
let after
if (end.offset < offset + length) {
const off = end.offset - offset
after = { ...middle, text: middle.text.slice(off) }
middle = { ...middle, text: middle.text.slice(0, off) }
}
if (start.offset > offset) {
const off = start.offset - offset
before = { ...middle, text: middle.text.slice(0, off) }
middle = { ...middle, text: middle.text.slice(off) }
}
Object.assign(middle, rest)
if (before) {
next.push(before)
}
next.push(middle)
if (after) {
next.push(after)
}
}
leaves = next
}
return leaves
}
const MemoizedText = React.memo(Text, (prev, next) => { const MemoizedText = React.memo(Text, (prev, next) => {
return ( return (
next.parent === prev.parent && next.parent === prev.parent &&

View File

@@ -1,5 +1,5 @@
import isPlainObject from 'is-plain-object' import isPlainObject from 'is-plain-object'
import { Path } from '..' import { Range } from '..'
/** /**
* `Text` objects represent the nodes that contain the actual text content of a * `Text` objects represent the nodes that contain the actual text content of a
@@ -83,4 +83,77 @@ export const Text = {
return true return true
}, },
/**
* Get the leaves for a text node given decorations.
*/
decorations(node: Text, decorations: Range[]): Text[] {
let leaves: Text[] = [{ ...node }]
for (const dec of decorations) {
const { anchor, focus, ...rest } = dec
const [start, end] = Range.edges(dec)
const next = []
let o = 0
for (const leaf of leaves) {
const { length } = leaf.text
const offset = o
o += length
// If the range encompases the entire leaf, add the range.
if (start.offset <= offset && end.offset >= offset + length) {
Object.assign(leaf, rest)
next.push(leaf)
continue
}
// If the range starts after the leaf, or ends before it, continue.
if (
start.offset > offset + length ||
end.offset < offset ||
(end.offset === offset && offset !== 0)
) {
next.push(leaf)
continue
}
// Otherwise we need to split the leaf, at the start, end, or both,
// and add the range to the middle intersecting section. Do the end
// split first since we don't need to update the offset that way.
let middle = leaf
let before
let after
if (end.offset < offset + length) {
const off = end.offset - offset
after = { ...middle, text: middle.text.slice(off) }
middle = { ...middle, text: middle.text.slice(0, off) }
}
if (start.offset > offset) {
const off = start.offset - offset
before = { ...middle, text: middle.text.slice(0, off) }
middle = { ...middle, text: middle.text.slice(off) }
}
Object.assign(middle, rest)
if (before) {
next.push(before)
}
next.push(middle)
if (after) {
next.push(after)
}
}
leaves = next
}
return leaves
},
} }

View File

@@ -0,0 +1,31 @@
import { Text } from 'slate'
export const input = [
{
anchor: {
path: [0],
offset: 2,
},
focus: {
path: [0],
offset: 3,
},
decoration: 'decoration',
},
]
export const test = decorations => {
return Text.decorations({ text: 'abc', mark: 'mark' }, decorations)
}
export const output = [
{
text: 'ab',
mark: 'mark',
},
{
text: 'c',
mark: 'mark',
decoration: 'decoration',
},
]

View File

@@ -0,0 +1,35 @@
import { Text } from 'slate'
export const input = [
{
anchor: {
path: [0],
offset: 1,
},
focus: {
path: [0],
offset: 2,
},
decoration: 'decoration',
},
]
export const test = decorations => {
return Text.decorations({ text: 'abc', mark: 'mark' }, decorations)
}
export const output = [
{
text: 'a',
mark: 'mark',
},
{
text: 'b',
mark: 'mark',
decoration: 'decoration',
},
{
text: 'c',
mark: 'mark',
},
]

View File

@@ -0,0 +1,49 @@
import { Text } from 'slate'
export const input = [
{
anchor: {
path: [0],
offset: 1,
},
focus: {
path: [0],
offset: 2,
},
decoration1: 'decoration1',
},
{
anchor: {
path: [0],
offset: 0,
},
focus: {
path: [0],
offset: 3,
},
decoration2: 'decoration2',
},
]
export const test = decorations => {
return Text.decorations({ text: 'abc', mark: 'mark' }, decorations)
}
export const output = [
{
text: 'a',
mark: 'mark',
decoration2: 'decoration2',
},
{
text: 'b',
mark: 'mark',
decoration1: 'decoration1',
decoration2: 'decoration2',
},
{
text: 'c',
mark: 'mark',
decoration2: 'decoration2',
},
]

View File

@@ -0,0 +1,31 @@
import { Text } from 'slate'
export const input = [
{
anchor: {
path: [0],
offset: 0,
},
focus: {
path: [0],
offset: 1,
},
decoration: 'decoration',
},
]
export const test = decorations => {
return Text.decorations({ text: 'abc', mark: 'mark' }, decorations)
}
export const output = [
{
text: 'a',
mark: 'mark',
decoration: 'decoration',
},
{
text: 'bc',
mark: 'mark',
},
]