diff --git a/frontend/appflowy_flutter/packages/appflowy_editor/lib/src/render/selection_menu/selection_menu_widget.dart b/frontend/appflowy_flutter/packages/appflowy_editor/lib/src/render/selection_menu/selection_menu_widget.dart index 3a88cfcd4a..a212692e20 100644 --- a/frontend/appflowy_flutter/packages/appflowy_editor/lib/src/render/selection_menu/selection_menu_widget.dart +++ b/frontend/appflowy_flutter/packages/appflowy_editor/lib/src/render/selection_menu/selection_menu_widget.dart @@ -324,7 +324,7 @@ class _SelectionMenuWidgetState extends State { _deleteLastCharacters(); return KeyEventResult.handled; } else if (event.character != null && - !arrowKeys.contains(event.logicalKey)) { + !arrowKeys.contains(event.logicalKey) && event.logicalKey != LogicalKeyboardKey.tab) { keyword += event.character!; _insertText(event.character!); return KeyEventResult.handled; @@ -339,7 +339,14 @@ class _SelectionMenuWidgetState extends State { newSelectedIndex -= 1; } else if (event.logicalKey == LogicalKeyboardKey.arrowDown) { newSelectedIndex += 1; + } else if (event.logicalKey == LogicalKeyboardKey.tab) { + newSelectedIndex += widget.maxItemInRow; + var currRow = (newSelectedIndex) % widget.maxItemInRow; + if (newSelectedIndex >= _showingItems.length) { + newSelectedIndex = (currRow + 1) % widget.maxItemInRow; + } } + if (newSelectedIndex != _selectedIndex) { setState(() { _selectedIndex = newSelectedIndex.clamp(0, _showingItems.length - 1); diff --git a/frontend/appflowy_flutter/packages/appflowy_editor/test/render/selection_menu/selection_menu_widget_test.dart b/frontend/appflowy_flutter/packages/appflowy_editor/test/render/selection_menu/selection_menu_widget_test.dart index 6b392cdebb..45bbea120a 100644 --- a/frontend/appflowy_flutter/packages/appflowy_editor/test/render/selection_menu/selection_menu_widget_test.dart +++ b/frontend/appflowy_flutter/packages/appflowy_editor/test/render/selection_menu/selection_menu_widget_test.dart @@ -118,6 +118,79 @@ void main() async { findsNothing, ); }); + + group('tab and arrow keys move selection in desired direction', () { + + testWidgets('left and right keys move selection in desired direction', + (tester) async { + final editor = await _prepare(tester); + + var initialSelection = getSelectedMenuItem(tester); + expect(defaultSelectionMenuItems.indexOf(initialSelection.item), 0); + + await editor.pressLogicKey(LogicalKeyboardKey.arrowRight); + + var newSelection = getSelectedMenuItem(tester); + expect(defaultSelectionMenuItems.indexOf(newSelection.item), 5); + + await editor.pressLogicKey(LogicalKeyboardKey.arrowLeft); + + var finalSelection = getSelectedMenuItem(tester); + expect(defaultSelectionMenuItems.indexOf(initialSelection.item), 0); + }); + + testWidgets('up and down keys move selection in desired direction', + (tester) async { + final editor = await _prepare(tester); + + var initialSelection = getSelectedMenuItem(tester); + expect(defaultSelectionMenuItems.indexOf(initialSelection.item), 0); + + await editor.pressLogicKey(LogicalKeyboardKey.arrowDown); + + var newSelection = getSelectedMenuItem(tester); + expect(defaultSelectionMenuItems.indexOf(newSelection.item), 1); + + await editor.pressLogicKey(LogicalKeyboardKey.arrowUp); + + var finalSelection = getSelectedMenuItem(tester); + expect(defaultSelectionMenuItems.indexOf(finalSelection.item), 0); + }); + + testWidgets('arrow keys and tab move same selection', + (tester) async { + final editor = await _prepare(tester); + + var initialSelection = getSelectedMenuItem(tester); + expect(defaultSelectionMenuItems.indexOf(initialSelection.item), 0); + + await editor.pressLogicKey(LogicalKeyboardKey.arrowDown); + + var newSelection = getSelectedMenuItem(tester); + expect(defaultSelectionMenuItems.indexOf(newSelection.item), 1); + + await editor.pressLogicKey(LogicalKeyboardKey.tab); + + var finalSelection = getSelectedMenuItem(tester); + expect(defaultSelectionMenuItems.indexOf(finalSelection.item), 6); + }); + + testWidgets('tab moves selection to next row Item on reaching end of current row', + (tester) async { + final editor = await _prepare(tester); + + final initialSelection = getSelectedMenuItem(tester); + + expect(defaultSelectionMenuItems.indexOf(initialSelection.item), 0); + + await editor.pressLogicKey(LogicalKeyboardKey.tab); + await editor.pressLogicKey(LogicalKeyboardKey.tab); + + final finalSelection = getSelectedMenuItem(tester); + + expect(defaultSelectionMenuItems.indexOf(finalSelection.item), 1); + }); + }); }); } @@ -178,3 +251,11 @@ Future _testDefaultSelectionMenuItems( expect(node?.attributes.check, false); } } + +SelectionMenuItemWidget getSelectedMenuItem(WidgetTester tester) { + return tester + .state(find.byWidgetPredicate( + (widget) => widget is SelectionMenuItemWidget && widget.isSelected, + )) + .widget as SelectionMenuItemWidget; +} \ No newline at end of file