fix: paste single line text will remove the children block (#1100)

* fix: paste single line text will remove the children block

* fix: ignore deletion in table cell blocl

* chore: update undo redo stack size and seal time

* chore: refactor undo logic

* Revert "chore: refactor undo logic"

This reverts commit 98d64528845eba23f145827d331606afeb2840e5.
This commit is contained in:
Lucas 2025-04-30 15:50:09 +08:00 • committed by GitHub
commit e56746ac65
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 27 additions and 19 deletions

View file

@ -47,7 +47,12 @@ extension SelectionTransform on EditorState {
/// and deletes the nodes expect for the first node.
///
/// For the other cases, this function just deletes all the nodes.
Future<bool> deleteSelection(Selection selection) async {
Future<bool> deleteSelection(
Selection selection, {
List<String> ignoreNodeTypes = const [
TableCellBlockKeys.type,
],
}) async {
// Nothing to do if the selection is collapsed.
if (selection.isCollapsed) {
return false;
@ -66,7 +71,7 @@ extension SelectionTransform on EditorState {
// or node.
if (nodes.length == 1) {
// If table cell is selected, clear the cell node child.
final node = nodes.first.type == TableCellBlockKeys.type
final node = ignoreNodeTypes.contains(nodes.first.type)
? nodes.first.children.first
: nodes.first;
if (node.delta != null) {
@ -75,7 +80,7 @@ extension SelectionTransform on EditorState {
selection.startIndex,
selection.length,
);
} else if (node.parent?.type != TableCellBlockKeys.type) {
} else if (!ignoreNodeTypes.contains(node.parent?.type)) {
transaction.deleteNode(node);
}
}
@ -92,7 +97,7 @@ extension SelectionTransform on EditorState {
// All other nodes can be deleted.
if (i != 0) {
// Never delete a table cell node child
if (node.parent?.type == TableCellBlockKeys.type) {
if (ignoreNodeTypes.contains(node.parent?.type)) {
if (!nodes.any((n) => n.id == node.parent?.parent?.id)) {
transaction.deleteText(
node,
@ -105,13 +110,13 @@ extension SelectionTransform on EditorState {
// node, So we should not delete the last node. Just delete part of
// the text inside selection
else if (node.id == nodes.last.id &&
nodes.first.parent?.type == TableCellBlockKeys.type) {
ignoreNodeTypes.contains(nodes.first.parent?.type)) {
transaction.deleteText(
node,
0,
selection.end.offset,
);
} else if (node.type != TableCellBlockKeys.type) {
} else if (!ignoreNodeTypes.contains(node.type)) {
transaction.deleteNode(node);
}
continue;
@ -122,7 +127,7 @@ extension SelectionTransform on EditorState {
// the text between the two nodes.
if (nodes.last.delta != null &&
![node.parent?.type, nodes.last.parent?.type]
.contains(TableCellBlockKeys.type)) {
.any((type) => ignoreNodeTypes.contains(type))) {
transaction.mergeText(
node,
nodes.last,
@ -154,8 +159,8 @@ extension SelectionTransform on EditorState {
else {
// If the last or first node is inside table we will only delete
// selection part of first node.
if (nodes.last.parent?.type == TableCellBlockKeys.type ||
node.parent?.type == TableCellBlockKeys.type) {
if (ignoreNodeTypes.contains(nodes.last.parent?.type) ||
ignoreNodeTypes.contains(node.parent?.type)) {
transaction.deleteText(
node,
selection.startIndex,

View file

@ -21,17 +21,18 @@ extension EditorCopyPaste on EditorState {
final insertedDelta = insertedNode.delta;
// if the node is empty paragraph (default), replace it with the inserted node.
if (delta.isEmpty && node.type == ParagraphBlockKeys.type) {
transaction.insertNode(
selection.end.path.next,
insertedNode,
);
final List<Node> combinedChildren = [
...insertedNode.children.map((e) => e.deepCopy()),
// if the original node has children, copy them to the inserted node.
...node.children.map((e) => e.deepCopy()),
];
insertedNode = insertedNode.copyWith(children: combinedChildren);
transaction.insertNode(selection.end.path, insertedNode);
transaction.deleteNode(node);
final path = calculatePath(selection.end.path, [insertedNode]);
final offset = calculateLength([insertedNode]);
transaction.afterSelection = Selection.collapsed(
Position(
path: path,
offset: offset,
path: selection.end.path,
offset: insertedDelta?.length ?? 0,
),
);
} else if (insertedDelta != null) {

View file

@ -92,8 +92,10 @@ enum TransactionTime {
class EditorState {
EditorState({
required this.document,
this.minHistoryItemDuration = const Duration(milliseconds: 200),
this.minHistoryItemDuration = const Duration(milliseconds: 50),
int? maxHistoryItemSize,
}) {
undoManager = UndoManager(maxHistoryItemSize ?? 200);
undoManager.state = this;
}
@ -252,7 +254,7 @@ class EditorState {
_sliceUpcomingAttributes = value;
}
final UndoManager undoManager = UndoManager();
late final UndoManager undoManager;
Transaction get transaction {
final transaction = Transaction(document: document);