Skip to content

Commit

Permalink
[SuperEditor] Convert empty task to paragraph on ENTER (Resolves #1898)…
Browse files Browse the repository at this point in the history
… (#2034)
  • Loading branch information
angelosilvestre authored and web-flow committed May 25, 2024
1 parent 8592c1f commit c5a5f79
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1792,6 +1792,11 @@ class CommonEditorOperations {
]);
}
} else if (extentNode is TaskNode) {
if (extentNode.text.text.isEmpty) {
// The task is empty. Convert it to a paragraph.
return convertToParagraph();
}

final splitOffset = (composer.selection!.extent.nodePosition as TextNodePosition).offset;

editor.execute([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,14 @@ class TextDeltasDocumentEditor {
]);
}
} else if (extentNode is TaskNode) {
if (extentNode.text.text.isEmpty) {
// The task is empty. Convert it to a paragraph.
editor.execute([
ConvertTextNodeToParagraphRequest(nodeId: extentNode.id),
]);
return;
}

final splitOffset = (caretPosition.nodePosition as TextNodePosition).offset;

editor.execute([
Expand Down
8 changes: 8 additions & 0 deletions super_editor/lib/src/default_editor/tasks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,14 @@ ExecutionInstruction enterToInsertNewTask({
return ExecutionInstruction.continueExecution;
}

if (node.text.text.isEmpty) {
// The task is empty. Convert it to a paragraph.
editContext.editor.execute([
ConvertTextNodeToParagraphRequest(nodeId: node.id),
]);
return ExecutionInstruction.haltExecution;
}

final splitOffset = (selection.extent.nodePosition as TextNodePosition).offset;

editContext.editor.execute([
Expand Down
101 changes: 101 additions & 0 deletions super_editor/test/super_editor/components/task_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -515,5 +515,106 @@ void main() {
expect(document.nodes.first, isA<ParagraphNode>());
expect((document.nodes.first as ParagraphNode).text.text, "This is a task");
});

testWidgetsOnAllPlatforms("converts task to paragraph when the user presses ENTER on an empty task",
(tester) async {
await _pumpSingleEmptyTaskApp(tester);

// Place the caret at the beginning of the task.
await tester.placeCaretInParagraph("1", 0);

// Press enter to convert the task into a paragraph.
await tester.pressEnter();

final document = SuperEditorInspector.findDocument()!;

// Ensure the task was converted to a paragraph.
expect(document.nodes.length, 1);
expect(document.nodes.first, isA<ParagraphNode>());
expect((document.nodes.first as ParagraphNode).text.text, "");
});

testWidgetsOnAndroid("converts task to paragraph upon new line insertion on an empty task", (tester) async {
await _pumpSingleEmptyTaskApp(tester);

// Place the caret at the beginning of the task.
await tester.placeCaretInParagraph("1", 0);

// Press enter to convert the task into a paragraph.
// On Android, pressing ENTER generates a "\n" insertion.
await tester.typeImeText("\n");

final document = SuperEditorInspector.findDocument()!;

// Ensure the task was converted to a paragraph.
expect(document.nodes.length, 1);
expect(document.nodes.first, isA<ParagraphNode>());
expect((document.nodes.first as ParagraphNode).text.text, "");
});

testWidgetsOnIos("converts task to paragraph new line input action on an empty task", (tester) async {
await _pumpSingleEmptyTaskApp(tester);

// Place the caret at the beginning of the task.
await tester.placeCaretInParagraph("1", 0);

// Press enter to convert the task into a paragraph.
// On iOS, pressing ENTER generates a newline action.
await tester.testTextInput.receiveAction(TextInputAction.newline);

final document = SuperEditorInspector.findDocument()!;

// Ensure the task was converted to a paragraph.
expect(document.nodes.length, 1);
expect(document.nodes.first, isA<ParagraphNode>());
expect((document.nodes.first as ParagraphNode).text.text, "");
});

testWidgetsOnWebDesktop("converts task to paragraph when the user presses ENTER on an empty task", (tester) async {
await _pumpSingleEmptyTaskApp(tester);

// Place the caret at the beginning of the task.
await tester.placeCaretInParagraph("1", 0);

// Press enter to convert the task into a paragraph.
// On Web, this generates both a newline input action and a key event.
await tester.pressEnter();
await tester.testTextInput.receiveAction(TextInputAction.newline);
await tester.pump();

final document = SuperEditorInspector.findDocument()!;

// Ensure the task was converted to a paragraph.
expect(document.nodes.length, 1);
expect(document.nodes.first, isA<ParagraphNode>());
expect((document.nodes.first as ParagraphNode).text.text, "");
});
});
}

Future<void> _pumpSingleEmptyTaskApp(WidgetTester tester) async {
final document = MutableDocument(
nodes: [
TaskNode(id: "1", text: AttributedText(), isComplete: false),
],
);

final composer = MutableDocumentComposer();
final editor = createDefaultDocumentEditor(document: document, composer: composer);

await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: SuperEditor(
editor: editor,
document: document,
composer: composer,
componentBuilders: [
TaskComponentBuilder(editor),
...defaultComponentBuilders,
],
),
),
),
);
}

0 comments on commit c5a5f79

Please sign in to comment.