fix(editor): a rich text field focused without a cursor puts it at the end

AppFlowy's editor takes the focus without a selection when it is focused
from outside, by Tab or by a field moving it there (Todo's quick add, its
down arrow into the description), so it showed no cursor and took no
typing until clicked. Focused so, it now places the cursor at the end of
its last text.

Whats-New: Moving into a text with Tab or the arrow keys now puts the cursor there, ready to type.
Whats-New-De: Wer mit Tab oder den Pfeiltasten in einen Text wechselt, hat den Cursor jetzt gleich dort und kann tippen.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-11-09 23:12:29 +01:00
commit 6356bed37d
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -1,4 +1,5 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:halkyon_editor/halkyon_editor.dart';
import 'package:material_ui/material_ui.dart';
@ -45,4 +46,63 @@ void main() {
.editorState;
expect(editorState.selection?.start.path, [2]);
});
group('Given an editor without a caret,', () {
late FocusNode focusNode;
Future<EditorState> pumpEditor(WidgetTester tester) async {
focusNode = FocusNode();
addTearDown(focusNode.dispose);
await tester.pumpWidget(
MaterialApp(
localizationsDelegates: editorTestDelegates,
home: Scaffold(
body: Column(
children: [
const TextField(key: Key('before'), autofocus: true),
SizedBox(
height: 200,
child: RichContentEditor(
initialContent: RichContent.plain('Water'),
focusNode: focusNode,
onChanged: (_) {},
),
),
],
),
),
),
);
await tester.pump(const Duration(seconds: 1));
return tester
.widget<AppFlowyEditor>(find.byType(AppFlowyEditor))
.editorState;
}
testWidgets('when its focus is asked for, then the caret is at the end '
'of its text.', (tester) async {
final editorState = await pumpEditor(tester);
expect(editorState.selection, isNull);
focusNode.requestFocus();
await tester.pump();
expect(focusNode.hasFocus, isTrue);
expect(
editorState.selection,
Selection.collapsed(Position(path: [0], offset: 5)),
);
});
testWidgets('when Tab leaves the field before it, then the caret is in '
'it.', (tester) async {
final editorState = await pumpEditor(tester);
await tester.sendKeyEvent(LogicalKeyboardKey.tab);
await tester.pump();
expect(focusNode.hasFocus, isTrue);
expect(editorState.selection, isNotNull);
});
});
}