Skip to content

Commit c8082d3

Browse files
feat: support exitting the link menu by pressing ESC
1 parent 8bfb37f commit c8082d3

File tree

7 files changed

+80
-21
lines changed

7 files changed

+80
-21
lines changed

lib/l10n/intl_en.arb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
"lightLightTint7": "Green",
9494
"lightLightTint8": "Aqua",
9595
"lightLightTint9": "Blue",
96+
"urlHint": "URL",
9697
"mobileHeading1": "Heading 1",
9798
"mobileHeading2": "Heading 2",
9899
"mobileHeading3": "Heading 3",

lib/src/editor/toolbar/desktop/items/link/link_menu.dart

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'package:appflowy_editor/src/editor_state.dart';
22
import 'package:appflowy_editor/src/infra/flowy_svg.dart';
33
import 'package:appflowy_editor/src/l10n/l10n.dart';
44
import 'package:flutter/material.dart';
5+
import 'package:flutter/services.dart';
56
import 'package:appflowy_editor/src/editor/toolbar/desktop/items/utils/overlay_util.dart';
67

78
class LinkMenu extends StatefulWidget {
@@ -13,6 +14,7 @@ class LinkMenu extends StatefulWidget {
1314
required this.onOpenLink,
1415
required this.onCopyLink,
1516
required this.onRemoveLink,
17+
required this.onDismiss,
1618
}) : super(key: key);
1719

1820
final String? linkText;
@@ -21,6 +23,7 @@ class LinkMenu extends StatefulWidget {
2123
final VoidCallback onOpenLink;
2224
final VoidCallback onCopyLink;
2325
final VoidCallback onRemoveLink;
26+
final VoidCallback onDismiss;
2427

2528
@override
2629
State<LinkMenu> createState() => _LinkMenuState();
@@ -81,27 +84,36 @@ class _LinkMenuState extends State<LinkMenu> {
8184
}
8285

8386
Widget _buildInput() {
84-
return TextField(
85-
focusNode: _focusNode,
86-
textAlign: TextAlign.left,
87-
controller: _textEditingController,
88-
onSubmitted: widget.onSubmitted,
89-
decoration: InputDecoration(
90-
hintText: 'URL',
91-
contentPadding: const EdgeInsets.all(16.0),
92-
isDense: true,
93-
suffixIcon: IconButton(
94-
padding: const EdgeInsets.all(4.0),
95-
icon: const FlowySvg(
96-
name: 'clear',
97-
width: 24,
98-
height: 24,
87+
return RawKeyboardListener(
88+
focusNode: FocusNode(),
89+
onKey: (key) {
90+
if (key is RawKeyDownEvent &&
91+
key.logicalKey == LogicalKeyboardKey.escape) {
92+
widget.onDismiss();
93+
}
94+
},
95+
child: TextField(
96+
focusNode: _focusNode,
97+
textAlign: TextAlign.left,
98+
controller: _textEditingController,
99+
onSubmitted: widget.onSubmitted,
100+
decoration: InputDecoration(
101+
hintText: AppFlowyEditorLocalizations.current.urlHint,
102+
contentPadding: const EdgeInsets.all(16.0),
103+
isDense: true,
104+
suffixIcon: IconButton(
105+
padding: const EdgeInsets.all(4.0),
106+
icon: const FlowySvg(
107+
name: 'clear',
108+
width: 24,
109+
height: 24,
110+
),
111+
onPressed: _textEditingController.clear,
112+
splashRadius: 5,
113+
),
114+
border: const OutlineInputBorder(
115+
borderRadius: BorderRadius.all(Radius.circular(12.0)),
99116
),
100-
onPressed: _textEditingController.clear,
101-
splashRadius: 5,
102-
),
103-
border: const OutlineInputBorder(
104-
borderRadius: BorderRadius.all(Radius.circular(12.0)),
105117
),
106118
),
107119
);

lib/src/editor/toolbar/desktop/items/link/link_toolbar_item.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ void showLinkMenu(
111111
editorState.apply(transaction);
112112
dismissOverlay();
113113
},
114+
onDismiss: dismissOverlay,
114115
);
115116
},
116117
).build();

lib/src/l10n/intl/messages_en.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ class MessageLookup extends MessageLookupByLibrary {
106106
"tint7": MessageLookupByLibrary.simpleMessage("Tint 7"),
107107
"tint8": MessageLookupByLibrary.simpleMessage("Tint 8"),
108108
"tint9": MessageLookupByLibrary.simpleMessage("Tint 9"),
109-
"underline": MessageLookupByLibrary.simpleMessage("Underline")
109+
"underline": MessageLookupByLibrary.simpleMessage("Underline"),
110+
"urlHint": MessageLookupByLibrary.simpleMessage("URL")
110111
};
111112
}

lib/src/l10n/l10n.dart

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/src/service/selection_service.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ class _AppFlowySelectionState extends State<AppFlowySelection>
249249
currentSelectedNodes = [];
250250
currentSelection.value = null;
251251

252+
_clearToolbar();
252253
clearCursor();
253254
// clear selection areas
254255
_selectionAreas

test/new/toolbar/desktop/items/link/link_menu_test.dart

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'package:appflowy_editor/src/core/document/text_delta.dart';
22
import 'package:appflowy_editor/src/editor/toolbar/desktop/items/link/link_menu.dart';
33
import 'package:flutter/material.dart';
4+
import 'package:flutter/services.dart';
45
import 'package:flutter_test/flutter_test.dart';
56
import '../../../../infra/testable_editor.dart';
67

@@ -20,6 +21,7 @@ void main() async {
2021
onSubmitted: (text) {
2122
submittedText = text;
2223
},
24+
onDismiss: () {},
2325
);
2426
final editor = tester.editor;
2527
await editor.startTesting();
@@ -92,5 +94,36 @@ void main() async {
9294

9395
await editor.dispose();
9496
});
97+
98+
testWidgets('test dismiss link menu by pressing ESC', (tester) async {
99+
var dismissed = false;
100+
101+
final linkMenu = LinkMenu(
102+
onOpenLink: () {},
103+
onCopyLink: () {},
104+
onRemoveLink: () {},
105+
onSubmitted: (text) {},
106+
onDismiss: () {
107+
dismissed = true;
108+
},
109+
);
110+
111+
await tester.pumpWidget(
112+
MaterialApp(
113+
home: Material(
114+
child: linkMenu,
115+
),
116+
),
117+
);
118+
119+
expect(find.byType(TextButton), findsNothing);
120+
expect(find.byType(TextField), findsOneWidget);
121+
122+
// Simulate keyboard press event for the Escape key
123+
await tester.sendKeyEvent(LogicalKeyboardKey.escape);
124+
await tester.pumpAndSettle();
125+
126+
expect(dismissed, true);
127+
});
95128
});
96129
}

0 commit comments

Comments
 (0)