feat: allow passing in a context menu builder (#1152)
* feat: allow passing in a context menu builder * test: fix test * chore: dart analyzer
This commit is contained in:
parent
daacca47da
commit
387a90ce39
5 changed files with 39 additions and 24 deletions
|
|
@ -26,7 +26,7 @@ class AppFlowyEditor extends StatefulWidget {
|
||||||
Map<String, BlockComponentBuilder>? blockComponentBuilders,
|
Map<String, BlockComponentBuilder>? blockComponentBuilders,
|
||||||
List<CharacterShortcutEvent>? characterShortcutEvents,
|
List<CharacterShortcutEvent>? characterShortcutEvents,
|
||||||
List<CommandShortcutEvent>? commandShortcutEvents,
|
List<CommandShortcutEvent>? commandShortcutEvents,
|
||||||
List<List<ContextMenuItem>>? contextMenuItems,
|
this.contextMenuBuilder,
|
||||||
this.contentInsertionConfiguration,
|
this.contentInsertionConfiguration,
|
||||||
this.editable = true,
|
this.editable = true,
|
||||||
this.autoFocus = false,
|
this.autoFocus = false,
|
||||||
|
|
@ -53,8 +53,7 @@ class AppFlowyEditor extends StatefulWidget {
|
||||||
characterShortcutEvents =
|
characterShortcutEvents =
|
||||||
characterShortcutEvents ?? standardCharacterShortcutEvents,
|
characterShortcutEvents ?? standardCharacterShortcutEvents,
|
||||||
commandShortcutEvents =
|
commandShortcutEvents =
|
||||||
commandShortcutEvents ?? standardCommandShortcutEvents,
|
commandShortcutEvents ?? standardCommandShortcutEvents;
|
||||||
contextMenuItems = contextMenuItems ?? standardContextMenuItems;
|
|
||||||
|
|
||||||
final EditorState editorState;
|
final EditorState editorState;
|
||||||
|
|
||||||
|
|
@ -122,16 +121,14 @@ class AppFlowyEditor extends StatefulWidget {
|
||||||
/// ```
|
/// ```
|
||||||
final List<CommandShortcutEvent> commandShortcutEvents;
|
final List<CommandShortcutEvent> commandShortcutEvents;
|
||||||
|
|
||||||
/// The context menu items.
|
/// The context menu builder.
|
||||||
///
|
///
|
||||||
/// They will be shown when the user right click on the editor.
|
/// It will be shown when the user right click on the editor.
|
||||||
/// Each item will be separated by a divider.
|
|
||||||
///
|
///
|
||||||
/// Defaults to [standardContextMenuItems].
|
/// Defaults to a standard implementation containing
|
||||||
|
/// [standardContextMenuItems].
|
||||||
///
|
///
|
||||||
/// If empty the context menu won't appear.
|
final ContextMenuWidgetBuilder? contextMenuBuilder;
|
||||||
///
|
|
||||||
final List<List<ContextMenuItem>>? contextMenuItems;
|
|
||||||
|
|
||||||
/// Provide a editorScrollController to control the scroll behavior
|
/// Provide a editorScrollController to control the scroll behavior
|
||||||
///
|
///
|
||||||
|
|
@ -345,7 +342,7 @@ class _AppFlowyEditorState extends State<AppFlowyEditor> {
|
||||||
cursorColor: widget.editorStyle.cursorColor,
|
cursorColor: widget.editorStyle.cursorColor,
|
||||||
selectionColor: widget.editorStyle.selectionColor,
|
selectionColor: widget.editorStyle.selectionColor,
|
||||||
showMagnifier: widget.showMagnifier,
|
showMagnifier: widget.showMagnifier,
|
||||||
contextMenuItems: widget.contextMenuItems,
|
contextMenuBuilder: widget.contextMenuBuilder,
|
||||||
dropTargetStyle: widget.dropTargetStyle,
|
dropTargetStyle: widget.dropTargetStyle,
|
||||||
child: child,
|
child: child,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ class DesktopSelectionServiceWidget extends StatefulWidget {
|
||||||
super.key,
|
super.key,
|
||||||
this.cursorColor = const Color(0xFF00BCF0),
|
this.cursorColor = const Color(0xFF00BCF0),
|
||||||
this.selectionColor = const Color(0xFF00BCF0),
|
this.selectionColor = const Color(0xFF00BCF0),
|
||||||
this.contextMenuItems,
|
this.contextMenuBuilder,
|
||||||
required this.child,
|
required this.child,
|
||||||
this.dropTargetStyle = const AppFlowyDropTargetStyle(),
|
this.dropTargetStyle = const AppFlowyDropTargetStyle(),
|
||||||
});
|
});
|
||||||
|
|
@ -19,7 +19,7 @@ class DesktopSelectionServiceWidget extends StatefulWidget {
|
||||||
final Widget child;
|
final Widget child;
|
||||||
final Color cursorColor;
|
final Color cursorColor;
|
||||||
final Color selectionColor;
|
final Color selectionColor;
|
||||||
final List<List<ContextMenuItem>>? contextMenuItems;
|
final ContextMenuWidgetBuilder? contextMenuBuilder;
|
||||||
final AppFlowyDropTargetStyle dropTargetStyle;
|
final AppFlowyDropTargetStyle dropTargetStyle;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -425,8 +425,8 @@ class _DesktopSelectionServiceWidgetState
|
||||||
void _showContextMenu(TapDownDetails details) {
|
void _showContextMenu(TapDownDetails details) {
|
||||||
_clearContextMenu();
|
_clearContextMenu();
|
||||||
|
|
||||||
// Don't trigger the context menu if there are no items
|
// Don't trigger the context menu if the builder is null
|
||||||
if (widget.contextMenuItems == null || widget.contextMenuItems!.isEmpty) {
|
if (widget.contextMenuBuilder == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -458,12 +458,14 @@ class _DesktopSelectionServiceWidgetState
|
||||||
editorState.renderBox?.localToGlobal(Offset.zero) ?? Offset.zero;
|
editorState.renderBox?.localToGlobal(Offset.zero) ?? Offset.zero;
|
||||||
final offset = details.localPosition + const Offset(10, 10) + baseOffset;
|
final offset = details.localPosition + const Offset(10, 10) + baseOffset;
|
||||||
final contextMenu = OverlayEntry(
|
final contextMenu = OverlayEntry(
|
||||||
builder: (context) => ContextMenu(
|
builder: (_) =>
|
||||||
position: offset,
|
widget.contextMenuBuilder?.call(
|
||||||
editorState: editorState,
|
context,
|
||||||
items: widget.contextMenuItems!,
|
offset,
|
||||||
onPressed: () => _clearContextMenu(),
|
editorState,
|
||||||
),
|
() => _clearContextMenu(),
|
||||||
|
) ??
|
||||||
|
SizedBox.shrink(),
|
||||||
);
|
);
|
||||||
|
|
||||||
_contextMenuAreas.add(contextMenu);
|
_contextMenuAreas.add(contextMenu);
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ class SelectionServiceWidget extends StatefulWidget {
|
||||||
this.cursorColor = const Color(0xFF00BCF0),
|
this.cursorColor = const Color(0xFF00BCF0),
|
||||||
this.selectionColor = const Color.fromARGB(53, 111, 201, 231),
|
this.selectionColor = const Color.fromARGB(53, 111, 201, 231),
|
||||||
this.showMagnifier = true,
|
this.showMagnifier = true,
|
||||||
this.contextMenuItems,
|
this.contextMenuBuilder,
|
||||||
this.dropTargetStyle,
|
this.dropTargetStyle,
|
||||||
required this.child,
|
required this.child,
|
||||||
});
|
});
|
||||||
|
|
@ -19,7 +19,7 @@ class SelectionServiceWidget extends StatefulWidget {
|
||||||
final Widget child;
|
final Widget child;
|
||||||
final Color cursorColor;
|
final Color cursorColor;
|
||||||
final Color selectionColor;
|
final Color selectionColor;
|
||||||
final List<List<ContextMenuItem>>? contextMenuItems;
|
final ContextMenuWidgetBuilder? contextMenuBuilder;
|
||||||
final AppFlowyDropTargetStyle? dropTargetStyle;
|
final AppFlowyDropTargetStyle? dropTargetStyle;
|
||||||
|
|
||||||
/// Show the magnifier or not.
|
/// Show the magnifier or not.
|
||||||
|
|
@ -47,7 +47,7 @@ class _SelectionServiceWidgetState extends State<SelectionServiceWidget>
|
||||||
key: forwardKey,
|
key: forwardKey,
|
||||||
cursorColor: widget.cursorColor,
|
cursorColor: widget.cursorColor,
|
||||||
selectionColor: widget.selectionColor,
|
selectionColor: widget.selectionColor,
|
||||||
contextMenuItems: widget.contextMenuItems,
|
contextMenuBuilder: widget.contextMenuBuilder,
|
||||||
dropTargetStyle:
|
dropTargetStyle:
|
||||||
widget.dropTargetStyle ?? const AppFlowyDropTargetStyle(),
|
widget.dropTargetStyle ?? const AppFlowyDropTargetStyle(),
|
||||||
child: widget.child,
|
child: widget.child,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,13 @@
|
||||||
import 'package:appflowy_editor/src/editor_state.dart';
|
import 'package:appflowy_editor/src/editor_state.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
typedef ContextMenuWidgetBuilder = Widget Function(
|
||||||
|
BuildContext context,
|
||||||
|
Offset position,
|
||||||
|
EditorState editorState,
|
||||||
|
VoidCallback onPressed,
|
||||||
|
);
|
||||||
|
|
||||||
class ContextMenuItem {
|
class ContextMenuItem {
|
||||||
ContextMenuItem({
|
ContextMenuItem({
|
||||||
required String Function() getName,
|
required String Function() getName,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
import 'package:appflowy_editor/src/editor/editor_component/service/ime/text_input_service.dart';
|
import 'package:appflowy_editor/src/editor/editor_component/service/ime/text_input_service.dart';
|
||||||
|
import 'package:appflowy_editor/src/service/context_menu/built_in_context_menu_item.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||||
|
|
@ -85,6 +86,14 @@ class TestableEditor {
|
||||||
...standardCharacterShortcutEvents,
|
...standardCharacterShortcutEvents,
|
||||||
formatGreaterHyphen,
|
formatGreaterHyphen,
|
||||||
],
|
],
|
||||||
|
contextMenuBuilder: (context, position, editorState, onPressed) {
|
||||||
|
return ContextMenu(
|
||||||
|
position: position,
|
||||||
|
editorState: editorState,
|
||||||
|
items: standardContextMenuItems,
|
||||||
|
onPressed: onPressed,
|
||||||
|
);
|
||||||
|
},
|
||||||
editorStyle: inMobile
|
editorStyle: inMobile
|
||||||
? EditorStyle.mobile(
|
? EditorStyle.mobile(
|
||||||
defaultTextDirection: defaultTextDirection,
|
defaultTextDirection: defaultTextDirection,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue