feat: support exitting the link menu by pressing ESC
This commit is contained in:
parent
8bfb37f691
commit
c8082d38df
7 changed files with 80 additions and 21 deletions
|
|
@ -93,6 +93,7 @@
|
||||||
"lightLightTint7": "Green",
|
"lightLightTint7": "Green",
|
||||||
"lightLightTint8": "Aqua",
|
"lightLightTint8": "Aqua",
|
||||||
"lightLightTint9": "Blue",
|
"lightLightTint9": "Blue",
|
||||||
|
"urlHint": "URL",
|
||||||
"mobileHeading1": "Heading 1",
|
"mobileHeading1": "Heading 1",
|
||||||
"mobileHeading2": "Heading 2",
|
"mobileHeading2": "Heading 2",
|
||||||
"mobileHeading3": "Heading 3",
|
"mobileHeading3": "Heading 3",
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import 'package:appflowy_editor/src/editor_state.dart';
|
||||||
import 'package:appflowy_editor/src/infra/flowy_svg.dart';
|
import 'package:appflowy_editor/src/infra/flowy_svg.dart';
|
||||||
import 'package:appflowy_editor/src/l10n/l10n.dart';
|
import 'package:appflowy_editor/src/l10n/l10n.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:appflowy_editor/src/editor/toolbar/desktop/items/utils/overlay_util.dart';
|
import 'package:appflowy_editor/src/editor/toolbar/desktop/items/utils/overlay_util.dart';
|
||||||
|
|
||||||
class LinkMenu extends StatefulWidget {
|
class LinkMenu extends StatefulWidget {
|
||||||
|
|
@ -13,6 +14,7 @@ class LinkMenu extends StatefulWidget {
|
||||||
required this.onOpenLink,
|
required this.onOpenLink,
|
||||||
required this.onCopyLink,
|
required this.onCopyLink,
|
||||||
required this.onRemoveLink,
|
required this.onRemoveLink,
|
||||||
|
required this.onDismiss,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final String? linkText;
|
final String? linkText;
|
||||||
|
|
@ -21,6 +23,7 @@ class LinkMenu extends StatefulWidget {
|
||||||
final VoidCallback onOpenLink;
|
final VoidCallback onOpenLink;
|
||||||
final VoidCallback onCopyLink;
|
final VoidCallback onCopyLink;
|
||||||
final VoidCallback onRemoveLink;
|
final VoidCallback onRemoveLink;
|
||||||
|
final VoidCallback onDismiss;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<LinkMenu> createState() => _LinkMenuState();
|
State<LinkMenu> createState() => _LinkMenuState();
|
||||||
|
|
@ -81,13 +84,21 @@ class _LinkMenuState extends State<LinkMenu> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildInput() {
|
Widget _buildInput() {
|
||||||
return TextField(
|
return RawKeyboardListener(
|
||||||
|
focusNode: FocusNode(),
|
||||||
|
onKey: (key) {
|
||||||
|
if (key is RawKeyDownEvent &&
|
||||||
|
key.logicalKey == LogicalKeyboardKey.escape) {
|
||||||
|
widget.onDismiss();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: TextField(
|
||||||
focusNode: _focusNode,
|
focusNode: _focusNode,
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
controller: _textEditingController,
|
controller: _textEditingController,
|
||||||
onSubmitted: widget.onSubmitted,
|
onSubmitted: widget.onSubmitted,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: 'URL',
|
hintText: AppFlowyEditorLocalizations.current.urlHint,
|
||||||
contentPadding: const EdgeInsets.all(16.0),
|
contentPadding: const EdgeInsets.all(16.0),
|
||||||
isDense: true,
|
isDense: true,
|
||||||
suffixIcon: IconButton(
|
suffixIcon: IconButton(
|
||||||
|
|
@ -104,6 +115,7 @@ class _LinkMenuState extends State<LinkMenu> {
|
||||||
borderRadius: BorderRadius.all(Radius.circular(12.0)),
|
borderRadius: BorderRadius.all(Radius.circular(12.0)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,7 @@ void showLinkMenu(
|
||||||
editorState.apply(transaction);
|
editorState.apply(transaction);
|
||||||
dismissOverlay();
|
dismissOverlay();
|
||||||
},
|
},
|
||||||
|
onDismiss: dismissOverlay,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
).build();
|
).build();
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||||
"tint7": MessageLookupByLibrary.simpleMessage("Tint 7"),
|
"tint7": MessageLookupByLibrary.simpleMessage("Tint 7"),
|
||||||
"tint8": MessageLookupByLibrary.simpleMessage("Tint 8"),
|
"tint8": MessageLookupByLibrary.simpleMessage("Tint 8"),
|
||||||
"tint9": MessageLookupByLibrary.simpleMessage("Tint 9"),
|
"tint9": MessageLookupByLibrary.simpleMessage("Tint 9"),
|
||||||
"underline": MessageLookupByLibrary.simpleMessage("Underline")
|
"underline": MessageLookupByLibrary.simpleMessage("Underline"),
|
||||||
|
"urlHint": MessageLookupByLibrary.simpleMessage("URL")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -611,6 +611,16 @@ class AppFlowyEditorLocalizations {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `URL`
|
||||||
|
String get urlHint {
|
||||||
|
return Intl.message(
|
||||||
|
'URL',
|
||||||
|
name: 'urlHint',
|
||||||
|
desc: '',
|
||||||
|
args: [],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// `Heading 1`
|
/// `Heading 1`
|
||||||
String get mobileHeading1 {
|
String get mobileHeading1 {
|
||||||
return Intl.message(
|
return Intl.message(
|
||||||
|
|
|
||||||
|
|
@ -249,6 +249,7 @@ class _AppFlowySelectionState extends State<AppFlowySelection>
|
||||||
currentSelectedNodes = [];
|
currentSelectedNodes = [];
|
||||||
currentSelection.value = null;
|
currentSelection.value = null;
|
||||||
|
|
||||||
|
_clearToolbar();
|
||||||
clearCursor();
|
clearCursor();
|
||||||
// clear selection areas
|
// clear selection areas
|
||||||
_selectionAreas
|
_selectionAreas
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:appflowy_editor/src/core/document/text_delta.dart';
|
import 'package:appflowy_editor/src/core/document/text_delta.dart';
|
||||||
import 'package:appflowy_editor/src/editor/toolbar/desktop/items/link/link_menu.dart';
|
import 'package:appflowy_editor/src/editor/toolbar/desktop/items/link/link_menu.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import '../../../../infra/testable_editor.dart';
|
import '../../../../infra/testable_editor.dart';
|
||||||
|
|
||||||
|
|
@ -20,6 +21,7 @@ void main() async {
|
||||||
onSubmitted: (text) {
|
onSubmitted: (text) {
|
||||||
submittedText = text;
|
submittedText = text;
|
||||||
},
|
},
|
||||||
|
onDismiss: () {},
|
||||||
);
|
);
|
||||||
final editor = tester.editor;
|
final editor = tester.editor;
|
||||||
await editor.startTesting();
|
await editor.startTesting();
|
||||||
|
|
@ -92,5 +94,36 @@ void main() async {
|
||||||
|
|
||||||
await editor.dispose();
|
await editor.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('test dismiss link menu by pressing ESC', (tester) async {
|
||||||
|
var dismissed = false;
|
||||||
|
|
||||||
|
final linkMenu = LinkMenu(
|
||||||
|
onOpenLink: () {},
|
||||||
|
onCopyLink: () {},
|
||||||
|
onRemoveLink: () {},
|
||||||
|
onSubmitted: (text) {},
|
||||||
|
onDismiss: () {
|
||||||
|
dismissed = true;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
home: Material(
|
||||||
|
child: linkMenu,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(find.byType(TextButton), findsNothing);
|
||||||
|
expect(find.byType(TextField), findsOneWidget);
|
||||||
|
|
||||||
|
// Simulate keyboard press event for the Escape key
|
||||||
|
await tester.sendKeyEvent(LogicalKeyboardKey.escape);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(dismissed, true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue