1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-31 02:49:56 +02:00

transform.delete and transform.insertFragment performance optimize (#5137)

* feat: transform.delete and transform.insertFragment performance optimize

* feat: add changeset

* feat: optimize code

Co-authored-by: mainhanu <chijun89@gmail.com>
This commit is contained in:
mainhanu
2022-10-19 20:38:34 +08:00
committed by GitHub
parent c19ab7853f
commit a2184d8657
3 changed files with 118 additions and 113 deletions

View File

@@ -0,0 +1,5 @@
---
'slate': minor
---
transform.delete and transform.insertFragment performance optimize

View File

@@ -1,4 +1,3 @@
import { produce } from 'immer'
import { Operation } from '..' import { Operation } from '..'
import { TextDirection } from './types' import { TextDirection } from './types'
@@ -373,125 +372,125 @@ export const Path: PathInterface = {
operation: Operation, operation: Operation,
options: PathTransformOptions = {} options: PathTransformOptions = {}
): Path | null { ): Path | null {
return produce(path, p => { if (!path) return null
const { affinity = 'forward' } = options
// PERF: Exit early if the operation is guaranteed not to have an effect. // PERF: use destructing instead of immer
if (!path || path?.length === 0) { const p = [...path]
return const { affinity = 'forward' } = options
}
if (p === null) { // PERF: Exit early if the operation is guaranteed not to have an effect.
return null if (path.length === 0) {
} return p
}
switch (operation.type) { switch (operation.type) {
case 'insert_node': { case 'insert_node': {
const { path: op } = operation const { path: op } = operation
if ( if (
Path.equals(op, p) || Path.equals(op, p) ||
Path.endsBefore(op, p) || Path.endsBefore(op, p) ||
Path.isAncestor(op, p) Path.isAncestor(op, p)
) { ) {
p[op.length - 1] += 1 p[op.length - 1] += 1
}
break
} }
case 'remove_node': { break
const { path: op } = operation }
if (Path.equals(op, p) || Path.isAncestor(op, p)) { case 'remove_node': {
const { path: op } = operation
if (Path.equals(op, p) || Path.isAncestor(op, p)) {
return null
} else if (Path.endsBefore(op, p)) {
p[op.length - 1] -= 1
}
break
}
case 'merge_node': {
const { path: op, position } = operation
if (Path.equals(op, p) || Path.endsBefore(op, p)) {
p[op.length - 1] -= 1
} else if (Path.isAncestor(op, p)) {
p[op.length - 1] -= 1
p[op.length] += position
}
break
}
case 'split_node': {
const { path: op, position } = operation
if (Path.equals(op, p)) {
if (affinity === 'forward') {
p[p.length - 1] += 1
} else if (affinity === 'backward') {
// Nothing, because it still refers to the right path.
} else {
return null return null
} else if (Path.endsBefore(op, p)) {
p[op.length - 1] -= 1
} }
} else if (Path.endsBefore(op, p)) {
break p[op.length - 1] += 1
} else if (Path.isAncestor(op, p) && path[op.length] >= position) {
p[op.length - 1] += 1
p[op.length] -= position
} }
case 'merge_node': { break
const { path: op, position } = operation
if (Path.equals(op, p) || Path.endsBefore(op, p)) {
p[op.length - 1] -= 1
} else if (Path.isAncestor(op, p)) {
p[op.length - 1] -= 1
p[op.length] += position
}
break
}
case 'split_node': {
const { path: op, position } = operation
if (Path.equals(op, p)) {
if (affinity === 'forward') {
p[p.length - 1] += 1
} else if (affinity === 'backward') {
// Nothing, because it still refers to the right path.
} else {
return null
}
} else if (Path.endsBefore(op, p)) {
p[op.length - 1] += 1
} else if (Path.isAncestor(op, p) && path[op.length] >= position) {
p[op.length - 1] += 1
p[op.length] -= position
}
break
}
case 'move_node': {
const { path: op, newPath: onp } = operation
// If the old and new path are the same, it's a no-op.
if (Path.equals(op, onp)) {
return
}
if (Path.isAncestor(op, p) || Path.equals(op, p)) {
const copy = onp.slice()
if (Path.endsBefore(op, onp) && op.length < onp.length) {
copy[op.length - 1] -= 1
}
return copy.concat(p.slice(op.length))
} else if (
Path.isSibling(op, onp) &&
(Path.isAncestor(onp, p) || Path.equals(onp, p))
) {
if (Path.endsBefore(op, p)) {
p[op.length - 1] -= 1
} else {
p[op.length - 1] += 1
}
} else if (
Path.endsBefore(onp, p) ||
Path.equals(onp, p) ||
Path.isAncestor(onp, p)
) {
if (Path.endsBefore(op, p)) {
p[op.length - 1] -= 1
}
p[onp.length - 1] += 1
} else if (Path.endsBefore(op, p)) {
if (Path.equals(onp, p)) {
p[onp.length - 1] += 1
}
p[op.length - 1] -= 1
}
break
}
} }
})
case 'move_node': {
const { path: op, newPath: onp } = operation
// If the old and new path are the same, it's a no-op.
if (Path.equals(op, onp)) {
return p
}
if (Path.isAncestor(op, p) || Path.equals(op, p)) {
const copy = onp.slice()
if (Path.endsBefore(op, onp) && op.length < onp.length) {
copy[op.length - 1] -= 1
}
return copy.concat(p.slice(op.length))
} else if (
Path.isSibling(op, onp) &&
(Path.isAncestor(onp, p) || Path.equals(onp, p))
) {
if (Path.endsBefore(op, p)) {
p[op.length - 1] -= 1
} else {
p[op.length - 1] += 1
}
} else if (
Path.endsBefore(onp, p) ||
Path.equals(onp, p) ||
Path.isAncestor(onp, p)
) {
if (Path.endsBefore(op, p)) {
p[op.length - 1] -= 1
}
p[onp.length - 1] += 1
} else if (Path.endsBefore(op, p)) {
if (Path.equals(onp, p)) {
p[onp.length - 1] += 1
}
p[op.length - 1] -= 1
}
break
}
}
return p
}, },
} }

View File

@@ -187,10 +187,11 @@ export const TextTransforms: TextTransforms = {
} }
} }
for (const pathRef of pathRefs) { pathRefs
const path = pathRef.unref()! .reverse()
Transforms.removeNodes(editor, { at: path, voids }) .map(r => r.unref())
} .filter((r): r is Path => r !== null)
.forEach(p => Transforms.removeNodes(editor, { at: p, voids }))
if (!endVoid) { if (!endVoid) {
const point = endRef.current! const point = endRef.current!