From 30700cd5130853261fcf2cd7e095b44036eb7300 Mon Sep 17 00:00:00 2001 From: "Lucas.Xu" Date: Tue, 18 Oct 2022 15:44:32 +0800 Subject: [PATCH] feat: implement context menu --- .../appflowy_editor/example/lib/main.dart | 14 ++ .../built_in_context_menu_item.dart | 28 ++++ .../service/context_menu/context_menu.dart | 90 +++++++++++ .../arrow_keys_handler.dart | 16 +- .../backspace_handler.dart | 21 +-- .../legacy/arrow_keys_handler.dart | 153 ------------------ .../slash_handler.dart | 13 +- .../whitespace_handler.dart | 5 - .../service/selection/selection_gesture.dart | 3 + .../lib/src/service/selection_service.dart | 41 +++++ .../built_in_shortcut_events.dart | 11 +- .../shortcut_event_handler.dart | 2 +- 12 files changed, 202 insertions(+), 195 deletions(-) create mode 100644 frontend/app_flowy/packages/appflowy_editor/lib/src/service/context_menu/built_in_context_menu_item.dart create mode 100644 frontend/app_flowy/packages/appflowy_editor/lib/src/service/context_menu/context_menu.dart delete mode 100644 frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/legacy/arrow_keys_handler.dart diff --git a/frontend/app_flowy/packages/appflowy_editor/example/lib/main.dart b/frontend/app_flowy/packages/appflowy_editor/example/lib/main.dart index 8d66b25b46..588804e9ac 100644 --- a/frontend/app_flowy/packages/appflowy_editor/example/lib/main.dart +++ b/frontend/app_flowy/packages/appflowy_editor/example/lib/main.dart @@ -65,6 +65,20 @@ class _MyHomePageState extends State { return Scaffold( extendBodyBehindAppBar: true, body: _buildEditor(context), + // body: Center( + // child: ContextMenu(editorState: EditorState.empty(), items: [ + // [ + // ContextMenuItem(name: 'ABCDEFGHIJKLM', onPressed: (editorState) {}), + // ContextMenuItem(name: 'A', onPressed: (editorState) {}), + // ContextMenuItem(name: 'A', onPressed: (editorState) {}) + // ], + // [ + // ContextMenuItem(name: 'B', onPressed: (editorState) {}), + // ContextMenuItem(name: 'B', onPressed: (editorState) {}), + // ContextMenuItem(name: 'B', onPressed: (editorState) {}) + // ] + // ]), + // ), floatingActionButton: _buildExpandableFab(), ); } diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/context_menu/built_in_context_menu_item.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/context_menu/built_in_context_menu_item.dart new file mode 100644 index 0000000000..b850f78e9a --- /dev/null +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/context_menu/built_in_context_menu_item.dart @@ -0,0 +1,28 @@ +import 'package:appflowy_editor/src/service/context_menu/context_menu.dart'; +import 'package:appflowy_editor/src/service/internal_key_event_handlers/copy_paste_handler.dart'; + +final builtInContextMenuItems = [ + [ + // cut + ContextMenuItem( + name: 'Cut', + onPressed: (editorState) { + cutEventHandler(editorState, null); + }, + ), + // copy + ContextMenuItem( + name: 'Copy', + onPressed: (editorState) { + copyEventHandler(editorState, null); + }, + ), + // Paste + ContextMenuItem( + name: 'Paste', + onPressed: (editorState) { + pasteEventHandler(editorState, null); + }, + ), + ], +]; diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/context_menu/context_menu.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/context_menu/context_menu.dart new file mode 100644 index 0000000000..80fceb03d1 --- /dev/null +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/context_menu/context_menu.dart @@ -0,0 +1,90 @@ +import 'package:appflowy_editor/src/editor_state.dart'; +import 'package:flutter/material.dart'; + +class ContextMenuItem { + ContextMenuItem({ + required this.name, + required this.onPressed, + }); + + final String name; + final void Function(EditorState editorState) onPressed; +} + +class ContextMenu extends StatelessWidget { + const ContextMenu({ + Key? key, + required this.position, + required this.editorState, + required this.items, + required this.onPressed, + }) : super(key: key); + + final Offset position; + final EditorState editorState; + final List> items; + final VoidCallback onPressed; + + @override + Widget build(BuildContext context) { + final children = []; + for (var i = 0; i < items.length; i++) { + for (var j = 0; j < items[i].length; j++) { + children.add( + Material( + child: InkWell( + hoverColor: const Color(0xFFE0F8FF), + customBorder: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6), + ), + onTap: () { + items[i][j].onPressed(editorState); + onPressed(); + }, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + items[i][j].name, + textAlign: TextAlign.start, + style: const TextStyle(fontSize: 14), + ), + ), + ), + ), + ); + } + if (i != items.length - 1) { + children.add(const Divider()); + } + } + + return Positioned( + top: position.dy, + left: position.dx, + child: Container( + padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 4), + constraints: const BoxConstraints( + minWidth: 140, + ), + decoration: BoxDecoration( + color: Colors.white, + boxShadow: [ + BoxShadow( + blurRadius: 5, + spreadRadius: 1, + color: Colors.black.withOpacity(0.1), + ), + ], + borderRadius: BorderRadius.circular(6.0), + ), + child: IntrinsicWidth( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: children, + ), + ), + ), + ); + } +} diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/arrow_keys_handler.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/arrow_keys_handler.dart index 80f139a4fe..94c857547b 100644 --- a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/arrow_keys_handler.dart +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/arrow_keys_handler.dart @@ -217,7 +217,7 @@ ShortcutEventHandler cursorEndSelect = (editorState, event) { return KeyEventResult.handled; }; -KeyEventResult cursorUp(EditorState editorState, RawKeyEvent event) { +ShortcutEventHandler cursorUp = (editorState, event) { final nodes = editorState.service.selectionService.currentSelectedNodes; final selection = editorState.service.selectionService.currentSelection.value?.normalized; @@ -229,9 +229,9 @@ KeyEventResult cursorUp(EditorState editorState, RawKeyEvent event) { upPosition == null ? null : Selection.collapsed(upPosition), ); return KeyEventResult.handled; -} +}; -KeyEventResult cursorDown(EditorState editorState, RawKeyEvent event) { +ShortcutEventHandler cursorDown = (editorState, event) { final nodes = editorState.service.selectionService.currentSelectedNodes; final selection = editorState.service.selectionService.currentSelection.value?.normalized; @@ -243,9 +243,9 @@ KeyEventResult cursorDown(EditorState editorState, RawKeyEvent event) { downPosition == null ? null : Selection.collapsed(downPosition), ); return KeyEventResult.handled; -} +}; -KeyEventResult cursorLeft(EditorState editorState, RawKeyEvent event) { +ShortcutEventHandler cursorLeft = (editorState, event) { final nodes = editorState.service.selectionService.currentSelectedNodes; final selection = editorState.service.selectionService.currentSelection.value?.normalized; @@ -265,9 +265,9 @@ KeyEventResult cursorLeft(EditorState editorState, RawKeyEvent event) { ); } return KeyEventResult.handled; -} +}; -KeyEventResult cursorRight(EditorState editorState, RawKeyEvent event) { +ShortcutEventHandler cursorRight = (editorState, event) { final nodes = editorState.service.selectionService.currentSelectedNodes; final selection = editorState.service.selectionService.currentSelection.value?.normalized; @@ -287,7 +287,7 @@ KeyEventResult cursorRight(EditorState editorState, RawKeyEvent event) { ); } return KeyEventResult.handled; -} +}; extension on Position { Position? goLeft(EditorState editorState) { diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/backspace_handler.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/backspace_handler.dart index cc0f06a072..69335e5145 100644 --- a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/backspace_handler.dart +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/backspace_handler.dart @@ -1,22 +1,9 @@ import 'package:appflowy_editor/src/infra/infra.dart'; import 'package:appflowy_editor/src/service/internal_key_event_handlers/number_list_helper.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:appflowy_editor/appflowy_editor.dart'; -// Handle delete text. -ShortcutEventHandler deleteTextHandler = (editorState, event) { - if (event.logicalKey == LogicalKeyboardKey.backspace) { - return _handleBackspace(editorState, event); - } - if (event.logicalKey == LogicalKeyboardKey.delete) { - return _handleDelete(editorState, event); - } - - return KeyEventResult.ignored; -}; - -KeyEventResult _handleBackspace(EditorState editorState, RawKeyEvent event) { +ShortcutEventHandler backspaceEventHandler = (editorState, event) { var selection = editorState.service.selectionService.currentSelection.value; if (selection == null) { return KeyEventResult.ignored; @@ -122,7 +109,7 @@ KeyEventResult _handleBackspace(EditorState editorState, RawKeyEvent event) { } return KeyEventResult.handled; -} +}; KeyEventResult _backDeleteToPreviousTextNode( EditorState editorState, @@ -182,7 +169,7 @@ KeyEventResult _backDeleteToPreviousTextNode( return KeyEventResult.handled; } -KeyEventResult _handleDelete(EditorState editorState, RawKeyEvent event) { +ShortcutEventHandler deleteEventHandler = (editorState, event) { var selection = editorState.service.selectionService.currentSelection.value; if (selection == null) { return KeyEventResult.ignored; @@ -238,7 +225,7 @@ KeyEventResult _handleDelete(EditorState editorState, RawKeyEvent event) { } return KeyEventResult.handled; -} +}; KeyEventResult _mergeNextLineIntoThisLine(EditorState editorState, TextNode textNode, Transaction transaction, Selection selection) { diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/legacy/arrow_keys_handler.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/legacy/arrow_keys_handler.dart deleted file mode 100644 index 523e13fbad..0000000000 --- a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/legacy/arrow_keys_handler.dart +++ /dev/null @@ -1,153 +0,0 @@ -import 'package:appflowy_editor/appflowy_editor.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; - -int _endOffsetOfNode(Node node) { - if (node is TextNode) { - return node.delta.length; - } - return 0; -} - -extension on Position { - Position? goLeft(EditorState editorState) { - final node = editorState.document.nodeAtPath(path)!; - if (offset == 0) { - final prevNode = node.previous; - if (prevNode != null) { - return Position( - path: prevNode.path, offset: _endOffsetOfNode(prevNode)); - } - return null; - } - - if (node is TextNode) { - return Position(path: path, offset: node.delta.prevRunePosition(offset)); - } else { - return Position(path: path, offset: offset); - } - } - - Position? goRight(EditorState editorState) { - final node = editorState.document.nodeAtPath(path)!; - final lengthOfNode = _endOffsetOfNode(node); - if (offset >= lengthOfNode) { - final nextNode = node.next; - if (nextNode != null) { - return Position(path: nextNode.path, offset: 0); - } - return null; - } - - if (node is TextNode) { - return Position(path: path, offset: node.delta.nextRunePosition(offset)); - } else { - return Position(path: path, offset: offset); - } - } -} - -Position? _goUp(EditorState editorState) { - final rects = editorState.service.selectionService.selectionRects; - if (rects.isEmpty) { - return null; - } - final first = rects.first; - final firstOffset = Offset(first.left, first.top); - final hitOffset = firstOffset - Offset(0, first.height * 0.5); - return editorState.service.selectionService.getPositionInOffset(hitOffset); -} - -Position? _goDown(EditorState editorState) { - final rects = editorState.service.selectionService.selectionRects; - if (rects.isEmpty) { - return null; - } - final first = rects.last; - final firstOffset = Offset(first.right, first.bottom); - final hitOffset = firstOffset + Offset(0, first.height * 0.5); - return editorState.service.selectionService.getPositionInOffset(hitOffset); -} - -KeyEventResult _handleShiftKey(EditorState editorState, RawKeyEvent event) { - final currentSelection = editorState.cursorSelection; - if (currentSelection == null) { - return KeyEventResult.ignored; - } - - if (event.logicalKey == LogicalKeyboardKey.arrowLeft) { - final leftPosition = currentSelection.end.goLeft(editorState); - editorState.updateCursorSelection(leftPosition == null - ? null - : Selection(start: currentSelection.start, end: leftPosition)); - return KeyEventResult.handled; - } else if (event.logicalKey == LogicalKeyboardKey.arrowRight) { - final rightPosition = currentSelection.start.goRight(editorState); - editorState.updateCursorSelection(rightPosition == null - ? null - : Selection(start: rightPosition, end: currentSelection.end)); - return KeyEventResult.handled; - } else if (event.logicalKey == LogicalKeyboardKey.arrowUp) { - final position = _goUp(editorState); - editorState.updateCursorSelection(position == null - ? null - : Selection(start: position, end: currentSelection.end)); - return KeyEventResult.handled; - } else if (event.logicalKey == LogicalKeyboardKey.arrowDown) { - final position = _goDown(editorState); - editorState.updateCursorSelection(position == null - ? null - : Selection(start: currentSelection.start, end: position)); - return KeyEventResult.handled; - } - return KeyEventResult.ignored; -} - -ShortcutEventHandler arrowKeysHandler = (editorState, event) { - if (event.isShiftPressed) { - return _handleShiftKey(editorState, event); - } - - final currentSelection = editorState.cursorSelection; - if (currentSelection == null) { - return KeyEventResult.ignored; - } - - if (event.logicalKey == LogicalKeyboardKey.arrowLeft) { - if (currentSelection.isCollapsed) { - final leftPosition = currentSelection.start.goLeft(editorState); - if (leftPosition != null) { - editorState.updateCursorSelection(Selection.collapsed(leftPosition)); - } - } else { - editorState.updateCursorSelection( - currentSelection.collapse(atStart: currentSelection.isBackward), - ); - } - return KeyEventResult.handled; - } else if (event.logicalKey == LogicalKeyboardKey.arrowRight) { - if (currentSelection.isCollapsed) { - final rightPosition = currentSelection.end.goRight(editorState); - if (rightPosition != null) { - editorState.updateCursorSelection(Selection.collapsed(rightPosition)); - } - } else { - editorState.updateCursorSelection( - currentSelection.collapse(atStart: !currentSelection.isBackward), - ); - } - return KeyEventResult.handled; - } else if (event.logicalKey == LogicalKeyboardKey.arrowUp) { - final position = _goUp(editorState); - editorState.updateCursorSelection( - position == null ? null : Selection.collapsed(position)); - return KeyEventResult.handled; - } else if (event.logicalKey == LogicalKeyboardKey.arrowDown) { - final position = _goDown(editorState); - editorState.updateCursorSelection( - position == null ? null : Selection.collapsed(position)); - return KeyEventResult.handled; - } - - return KeyEventResult.ignored; -}; diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/slash_handler.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/slash_handler.dart index 9ab6d337b1..9fa7eacce6 100644 --- a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/slash_handler.dart +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/slash_handler.dart @@ -4,14 +4,9 @@ import 'package:appflowy_editor/src/render/selection_menu/selection_menu_service import 'package:appflowy_editor/src/extensions/node_extensions.dart'; import 'package:appflowy_editor/src/service/shortcut_event/shortcut_event_handler.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; SelectionMenuService? _selectionMenuService; ShortcutEventHandler slashShortcutHandler = (editorState, event) { - if (event.logicalKey != LogicalKeyboardKey.slash) { - return KeyEventResult.ignored; - } - final textNodes = editorState.service.selectionService.currentSelectedNodes .whereType(); if (textNodes.length != 1) { @@ -26,8 +21,12 @@ ShortcutEventHandler slashShortcutHandler = (editorState, event) { return KeyEventResult.ignored; } final transaction = editorState.transaction - ..replaceText(textNode, selection.start.offset, - selection.end.offset - selection.start.offset, event.character ?? ''); + ..replaceText( + textNode, + selection.start.offset, + selection.end.offset - selection.start.offset, + '/', + ); editorState.apply(transaction); WidgetsBinding.instance.addPostFrameCallback((_) { diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/whitespace_handler.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/whitespace_handler.dart index b63f20155c..210a9a703e 100644 --- a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/whitespace_handler.dart +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/whitespace_handler.dart @@ -1,7 +1,6 @@ import 'package:appflowy_editor/src/core/transform/transaction.dart'; import 'package:appflowy_editor/src/service/shortcut_event/shortcut_event_handler.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:appflowy_editor/src/core/legacy/built_in_attribute_keys.dart'; import 'package:appflowy_editor/src/core/document/node.dart'; import 'package:appflowy_editor/src/core/location/position.dart'; @@ -24,10 +23,6 @@ const _unCheckboxListSymbols = ['[]', '-[]']; final _numberRegex = RegExp(r'^(\d+)\.'); ShortcutEventHandler whiteSpaceHandler = (editorState, event) { - if (event.logicalKey != LogicalKeyboardKey.space) { - return KeyEventResult.ignored; - } - /// Process markdown input style. /// /// like, #, *, -, 1., -[], diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/selection/selection_gesture.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/selection/selection_gesture.dart index 11a6326d26..e233b35446 100644 --- a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/selection/selection_gesture.dart +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/selection/selection_gesture.dart @@ -13,6 +13,7 @@ class SelectionGestureDetector extends StatefulWidget { this.onTapDown, this.onDoubleTapDown, this.onTripleTapDown, + this.onSecondaryTapDown, this.onPanStart, this.onPanUpdate, this.onPanEnd, @@ -27,6 +28,7 @@ class SelectionGestureDetector extends StatefulWidget { final GestureTapDownCallback? onTapDown; final GestureTapDownCallback? onDoubleTapDown; final GestureTapDownCallback? onTripleTapDown; + final GestureTapDownCallback? onSecondaryTapDown; final GestureDragStartCallback? onPanStart; final GestureDragUpdateCallback? onPanUpdate; final GestureDragEndCallback? onPanEnd; @@ -60,6 +62,7 @@ class SelectionGestureDetectorState extends State { () => TapGestureRecognizer(), (recognizer) { recognizer.onTapDown = _tapDownDelegate; + recognizer.onSecondaryTapDown = widget.onSecondaryTapDown; }, ), }, diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/selection_service.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/selection_service.dart index a5f27e9664..e562db0f7e 100644 --- a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/selection_service.dart +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/selection_service.dart @@ -1,4 +1,6 @@ import 'package:appflowy_editor/src/infra/log.dart'; +import 'package:appflowy_editor/src/service/context_menu/built_in_context_menu_item.dart'; +import 'package:appflowy_editor/src/service/context_menu/context_menu.dart'; import 'package:flutter/material.dart'; import 'package:appflowy_editor/src/core/document/node.dart'; @@ -108,6 +110,7 @@ class _AppFlowySelectionState extends State final List selectionRects = []; final List _selectionAreas = []; final List _cursorAreas = []; + final List _contextMenuAreas = []; // OverlayEntry? _debugOverlay; @@ -156,6 +159,7 @@ class _AppFlowySelectionState extends State onPanUpdate: _onPanUpdate, onPanEnd: _onPanEnd, onTapDown: _onTapDown, + onSecondaryTapDown: _onSecondaryTapDown, onDoubleTapDown: _onDoubleTapDown, onTripleTapDown: _onTripleTapDown, child: widget.child, @@ -232,6 +236,9 @@ class _AppFlowySelectionState extends State // hide toolbar editorState.service.toolbarService?.hide(); + + // clear context menu + _clearContextMenu(); } @override @@ -242,6 +249,12 @@ class _AppFlowySelectionState extends State ..clear(); } + void _clearContextMenu() { + _contextMenuAreas + ..forEach((overlay) => overlay.remove()) + ..clear(); + } + @override Node? getNodeInOffset(Offset offset) { final sortedNodes = @@ -311,6 +324,20 @@ class _AppFlowySelectionState extends State _enableInteraction(); } + void _onSecondaryTapDown(TapDownDetails details) { + // if selection is null, or + // selection.isCollapsedand and the selected node is TextNode. + // try to select the word. + final selection = currentSelection.value; + if (selection == null || + (selection.isCollapsed == true && + currentSelectedNodes.first is TextNode)) { + _onDoubleTapDown(details); + } + + _showContextMenu(details); + } + void _onPanStart(DragStartDetails details) { clearSelection(); @@ -477,6 +504,20 @@ class _AppFlowySelectionState extends State _cursorKey.currentState?.unwrapOrNull()?.show(); } + void _showContextMenu(TapDownDetails details) { + final contextMenu = OverlayEntry( + builder: (context) => ContextMenu( + position: details.globalPosition, + editorState: editorState, + items: builtInContextMenuItems, + onPressed: () => _clearContextMenu(), + ), + ); + + _contextMenuAreas.add(contextMenu); + Overlay.of(context)?.insert(contextMenu); + } + void _scrollUpOrDownIfNeeded() { final dy = editorState.service.scrollService?.dy; final selectNodes = currentSelectedNodes; diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/shortcut_event/built_in_shortcut_events.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/shortcut_event/built_in_shortcut_events.dart index b07e8bde17..0b6a006cc3 100644 --- a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/shortcut_event/built_in_shortcut_events.dart +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/shortcut_event/built_in_shortcut_events.dart @@ -208,12 +208,15 @@ List builtInShortcutEvents = [ command: 'end', handler: cursorEnd, ), - - // TODO: split the keys. + ShortcutEvent( + key: 'Delete Text by backspace', + command: 'backspace', + handler: backspaceEventHandler, + ), ShortcutEvent( key: 'Delete Text', - command: 'delete,backspace', - handler: deleteTextHandler, + command: 'delete', + handler: deleteEventHandler, ), ShortcutEvent( key: 'selection menu', diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/shortcut_event/shortcut_event_handler.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/shortcut_event/shortcut_event_handler.dart index 2cb00ff198..07719e045d 100644 --- a/frontend/app_flowy/packages/appflowy_editor/lib/src/service/shortcut_event/shortcut_event_handler.dart +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/service/shortcut_event/shortcut_event_handler.dart @@ -3,5 +3,5 @@ import 'package:flutter/material.dart'; typedef ShortcutEventHandler = KeyEventResult Function( EditorState editorState, - RawKeyEvent event, + RawKeyEvent? event, );