diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/render/link_menu/link_menu.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/render/link_menu/link_menu.dart index 3ebf87f4fa..679bea09f7 100644 --- a/frontend/app_flowy/packages/appflowy_editor/lib/src/render/link_menu/link_menu.dart +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/render/link_menu/link_menu.dart @@ -21,12 +21,21 @@ class LinkMenu extends StatefulWidget { class _LinkMenuState extends State { final _textEditingController = TextEditingController(); + final _focusNode = FocusNode(); @override void initState() { super.initState(); _textEditingController.text = widget.linkText ?? ''; + _focusNode.requestFocus(); + } + + @override + void dispose() { + _focusNode.dispose(); + + super.dispose(); } @override @@ -88,7 +97,7 @@ class _LinkMenuState extends State { Widget _buildInput() { return TextField( - autofocus: true, + focusNode: _focusNode, style: const TextStyle(fontSize: 14.0), textAlign: TextAlign.left, controller: _textEditingController, @@ -112,11 +121,7 @@ class _LinkMenuState extends State { required VoidCallback onPressed, }) { return TextButton.icon( - icon: FlowySvg( - name: iconName, - width: 20.0, - height: 20.0, - ), + icon: FlowySvg(name: iconName), style: TextButton.styleFrom( minimumSize: const Size.fromHeight(40), padding: EdgeInsets.zero, diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/render/toolbar/toolbar_item.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/render/toolbar/toolbar_item.dart index 49413311d2..a068722cb2 100644 --- a/frontend/app_flowy/packages/appflowy_editor/lib/src/render/toolbar/toolbar_item.dart +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/render/toolbar/toolbar_item.dart @@ -13,12 +13,14 @@ typedef ToolbarShowValidator = bool Function(EditorState editorState); class ToolbarItem { ToolbarItem({ + required this.id, required this.icon, this.tooltipsMessage = '', required this.validator, required this.handler, }); + final String id; final Widget icon; final String tooltipsMessage; final ToolbarShowValidator validator; @@ -26,6 +28,7 @@ class ToolbarItem { factory ToolbarItem.divider() { return ToolbarItem( + id: 'divider', icon: const FlowySvg(name: 'toolbar/divider'), validator: (editorState) => true, handler: (editorState, context) {}, @@ -35,18 +38,21 @@ class ToolbarItem { List defaultToolbarItems = [ ToolbarItem( + id: 'appflowy.toolbar.h1', tooltipsMessage: 'Heading 1', icon: const FlowySvg(name: 'toolbar/h1'), validator: _onlyShowInSingleTextSelection, handler: (editorState, context) => formatHeading(editorState, StyleKey.h1), ), ToolbarItem( + id: 'appflowy.toolbar.h2', tooltipsMessage: 'Heading 2', icon: const FlowySvg(name: 'toolbar/h2'), validator: _onlyShowInSingleTextSelection, handler: (editorState, context) => formatHeading(editorState, StyleKey.h2), ), ToolbarItem( + id: 'appflowy.toolbar.h3', tooltipsMessage: 'Heading 3', icon: const FlowySvg(name: 'toolbar/h3'), validator: _onlyShowInSingleTextSelection, @@ -54,24 +60,28 @@ List defaultToolbarItems = [ ), ToolbarItem.divider(), ToolbarItem( + id: 'appflowy.toolbar.bold', tooltipsMessage: 'Bold', icon: const FlowySvg(name: 'toolbar/bold'), validator: _showInTextSelection, handler: (editorState, context) => formatBold(editorState), ), ToolbarItem( + id: 'appflowy.toolbar.italic', tooltipsMessage: 'Italic', icon: const FlowySvg(name: 'toolbar/italic'), validator: _showInTextSelection, handler: (editorState, context) => formatItalic(editorState), ), ToolbarItem( + id: 'appflowy.toolbar.underline', tooltipsMessage: 'Underline', icon: const FlowySvg(name: 'toolbar/underline'), validator: _showInTextSelection, handler: (editorState, context) => formatUnderline(editorState), ), ToolbarItem( + id: 'appflowy.toolbar.strikethrough', tooltipsMessage: 'Strikethrough', icon: const FlowySvg(name: 'toolbar/strikethrough'), validator: _showInTextSelection, @@ -79,12 +89,14 @@ List defaultToolbarItems = [ ), ToolbarItem.divider(), ToolbarItem( + id: 'appflowy.toolbar.quote', tooltipsMessage: 'Quote', icon: const FlowySvg(name: 'toolbar/quote'), validator: _onlyShowInSingleTextSelection, handler: (editorState, context) => formatQuote(editorState), ), ToolbarItem( + id: 'appflowy.toolbar.bulleted_list', tooltipsMessage: 'Bulleted list', icon: const FlowySvg(name: 'toolbar/bulleted_list'), validator: _onlyShowInSingleTextSelection, @@ -92,12 +104,14 @@ List defaultToolbarItems = [ ), ToolbarItem.divider(), ToolbarItem( + id: 'appflowy.toolbar.link', tooltipsMessage: 'Link', icon: const FlowySvg(name: 'toolbar/link'), validator: _onlyShowInSingleTextSelection, handler: (editorState, context) => _showLinkMenu(editorState, context), ), ToolbarItem( + id: 'appflowy.toolbar.highlight', tooltipsMessage: 'Highlight', icon: const FlowySvg(name: 'toolbar/highlight'), validator: _showInTextSelection, @@ -152,9 +166,7 @@ void _showLinkMenu(EditorState editorState, BuildContext context) { linkText: linkText, onSubmitted: (text) { TransactionBuilder(editorState) - ..formatText(node, index, length, { - StyleKey.href: text, - }) + ..formatText(node, index, length, {StyleKey.href: text}) ..commit(); _dismissLinkMenu(); }, @@ -164,9 +176,7 @@ void _showLinkMenu(EditorState editorState, BuildContext context) { }, onRemoveLink: () { TransactionBuilder(editorState) - ..formatText(node, index, length, { - StyleKey.href: null, - }) + ..formatText(node, index, length, {StyleKey.href: null}) ..commit(); _dismissLinkMenu(); }, @@ -177,6 +187,7 @@ void _showLinkMenu(EditorState editorState, BuildContext context) { Overlay.of(context)?.insert(_linkMenuOverlay!); editorState.service.scrollService?.disable(); + editorState.service.keyboardService?.disable(); editorState.service.selectionService.currentSelection .addListener(_dismissLinkMenu); } @@ -186,6 +197,7 @@ void _dismissLinkMenu() { _linkMenuOverlay = null; _editorState?.service.scrollService?.enable(); + _editorState?.service.keyboardService?.enable(); _editorState?.service.selectionService.currentSelection .removeListener(_dismissLinkMenu); _editorState = null; diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/update_text_style_by_command_x_handler.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/update_text_style_by_command_x_handler.dart index 0eb926525b..00b304f527 100644 --- a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/update_text_style_by_command_x_handler.dart +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/update_text_style_by_command_x_handler.dart @@ -36,6 +36,12 @@ AppFlowyKeyEventHandler updateTextStyleByCommandXHandler = event.isShiftPressed) { formatHighlight(editorState); return KeyEventResult.handled; + } else if (event.logicalKey == LogicalKeyboardKey.keyK) { + if (editorState.service.toolbarService + ?.triggerHandler('appflowy.toolbar.link') == + true) { + return KeyEventResult.handled; + } } return KeyEventResult.ignored; diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/toolbar_service.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/toolbar_service.dart index fe4a2beace..290fe4b4bb 100644 --- a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/toolbar_service.dart +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/toolbar_service.dart @@ -11,6 +11,9 @@ abstract class FlowyToolbarService { /// Hide the toolbar widget. void hide(); + + /// Trigger the specified handler. + bool triggerHandler(String id); } class FlowyToolbar extends StatefulWidget { @@ -55,6 +58,17 @@ class _FlowyToolbarState extends State _toolbarOverlay = null; } + @override + bool triggerHandler(String id) { + final items = defaultToolbarItems.where((item) => item.id == id); + if (items.length != 1) { + assert(items.length == 1, 'The toolbar item\'s id must be unique'); + return false; + } + items.first.handler(widget.editorState, context); + return true; + } + @override Widget build(BuildContext context) { return Container(