feat : allow developer to change toolbar color as well as option to show default toolbar items and html to document converter added (#58)

* change toolbar and added export so developer can modify according to its need

* revert some chages from examples

* html to document convertion added

* test added

* code formated

* node to html added image parameter

* toolbar color and elevation added in editor stylee

* code formated

* remove duplicated exports

* fix test improts and formating
This commit is contained in:
Ali Hassan 2023-04-14 07:10:03 +05:00 • committed by GitHub
commit 865195f8c6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 71 additions and 34 deletions

View file

@ -27,7 +27,6 @@ export 'src/service/input_service.dart';
export 'src/service/shortcut_event/keybinding.dart';
export 'src/service/shortcut_event/shortcut_event.dart';
export 'src/service/shortcut_event/shortcut_event_handler.dart';
export 'src/extensions/attributes_extension.dart';
export 'src/render/rich_text/default_selectable.dart';
export 'src/render/rich_text/flowy_rich_text.dart';
export 'src/render/selection_menu/selection_menu_widget.dart';
@ -45,7 +44,11 @@ export 'src/plugins/quill_delta/delta_document_encoder.dart';
export 'src/commands/text/text_commands.dart';
export 'src/commands/command_extension.dart';
export 'src/render/toolbar/toolbar_item.dart';
export 'src/extensions/node_extensions.dart';
export 'src/render/action_menu/action_menu.dart';
export 'src/render/action_menu/action_menu_item.dart';
export 'src/core/document/node_iterator.dart';
export 'src/infra/flowy_svg.dart';
export 'src/extensions/extensions.dart';
export 'src/service/default_text_operations/format_rich_text_style.dart';
export 'src/infra/html_converter.dart';
export 'src/service/internal_key_event_handlers/copy_paste_handler.dart';

View file

@ -0,0 +1,9 @@
export 'attributes_extension.dart';
export 'color_extension.dart';
export 'editor_state_extensions.dart';
export 'node_extensions.dart';
export 'object_extensions.dart';
export 'text_node_extensions.dart';
export 'text_style_extension.dart';
export 'url_launcher_extension.dart';

View file

@ -10,6 +10,8 @@ import 'package:html/parser.dart' show parse;
import 'package:html/dom.dart' as html;
import 'package:appflowy_editor/src/core/legacy/built_in_attribute_keys.dart';
import '../core/document/document.dart';
class HTMLTag {
static const h1 = "h1";
static const h2 = "h2";
@ -60,6 +62,16 @@ class HTMLToNodesConverter {
return _handleContainer(childNodes);
}
Document toDocument() {
final childNodes = _document.body?.nodes.toList() ?? <html.Node>[];
return Document.fromJson({
"document": {
"type": "editor",
"children": _handleContainer(childNodes).map((e) => e.toJson()).toList()
}
});
}
List<Node> _handleContainer(List<html.Node> childNodes) {
final delta = Delta();
final result = <Node>[];
@ -432,6 +444,12 @@ class NodesToHTMLConverter {
} else {
_addTextNode(textNode);
}
} else if (node.type == "image") {
final textNode = node;
final anchor = html.Element.tag(HTMLTag.image);
anchor.attributes["src"] = textNode.attributes["image_src"];
_result.add(anchor);
}
// TODO: handle image and other blocks
}

View file

@ -1,5 +1,4 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor/src/infra/flowy_svg.dart';
import 'package:flutter/material.dart';
/// Represents a single action inside an action menu.

View file

@ -1,7 +1,6 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor/src/render/rich_text/built_in_text_widget.dart';
import 'package:appflowy_editor/src/extensions/text_style_extension.dart';
import 'package:flutter/material.dart';
import 'package:appflowy_editor/src/extensions/theme_extension.dart';

View file

@ -22,6 +22,8 @@ class EditorStyle extends ThemeExtension<EditorStyle> {
final Color? selectionMenuItemSelectedTextColor;
final Color? selectionMenuItemSelectedIconColor;
final Color? selectionMenuItemSelectedColor;
final Color? toolbarColor;
final double toolbarElevation;
// Text styles
final EdgeInsets? textPadding;
@ -49,6 +51,8 @@ class EditorStyle extends ThemeExtension<EditorStyle> {
required this.selectionMenuItemSelectedTextColor,
required this.selectionMenuItemSelectedIconColor,
required this.selectionMenuItemSelectedColor,
required this.toolbarColor,
required this.toolbarElevation,
required this.textPadding,
required this.textStyle,
required this.placeholderTextStyle,
@ -74,6 +78,8 @@ class EditorStyle extends ThemeExtension<EditorStyle> {
Color? selectionMenuItemSelectedTextColor,
Color? selectionMenuItemSelectedIconColor,
Color? selectionMenuItemSelectedColor,
Color? toolbarColor,
double? toolbarElevation,
TextStyle? textStyle,
TextStyle? placeholderTextStyle,
TextStyle? bold,
@ -102,6 +108,8 @@ class EditorStyle extends ThemeExtension<EditorStyle> {
this.selectionMenuItemSelectedIconColor,
selectionMenuItemSelectedColor:
selectionMenuItemSelectedColor ?? this.selectionMenuItemSelectedColor,
toolbarColor: toolbarColor ?? this.toolbarColor,
toolbarElevation: toolbarElevation ?? this.toolbarElevation,
textPadding: textPadding ?? textPadding,
textStyle: textStyle ?? this.textStyle,
placeholderTextStyle: placeholderTextStyle ?? this.placeholderTextStyle,
@ -160,6 +168,8 @@ class EditorStyle extends ThemeExtension<EditorStyle> {
other.selectionMenuItemSelectedColor,
t,
),
toolbarColor: Color.lerp(toolbarColor, other.toolbarColor, t),
toolbarElevation: toolbarElevation,
textStyle: TextStyle.lerp(textStyle, other.textStyle, t),
placeholderTextStyle:
TextStyle.lerp(placeholderTextStyle, other.placeholderTextStyle, t),
@ -189,6 +199,8 @@ class EditorStyle extends ThemeExtension<EditorStyle> {
selectionMenuItemSelectedTextColor: const Color.fromARGB(255, 56, 91, 247),
selectionMenuItemSelectedIconColor: const Color.fromARGB(255, 56, 91, 247),
selectionMenuItemSelectedColor: const Color(0xFFE0F8FF),
toolbarColor: const Color(0xFF333333),
toolbarElevation: 0.0,
textPadding: const EdgeInsets.symmetric(vertical: 8.0),
textStyle: const TextStyle(fontSize: 16.0, color: Colors.black),
placeholderTextStyle: const TextStyle(fontSize: 16.0, color: Colors.grey),
@ -222,5 +234,7 @@ class EditorStyle extends ThemeExtension<EditorStyle> {
selectionMenuItemSelectedTextColor: const Color(0xFF131720),
selectionMenuItemSelectedIconColor: const Color(0xFF131720),
selectionMenuItemSelectedColor: const Color(0xFF00BCF0),
toolbarColor: const Color(0xFF131720),
toolbarElevation: 0.0,
);
}

View file

@ -1,5 +1,4 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor/src/infra/flowy_svg.dart';
import 'package:flutter/material.dart';
Iterable<ThemeExtension<dynamic>> get lightPluginStyleExtension => [

View file

@ -1,13 +1,8 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor/src/extensions/url_launcher_extension.dart';
import 'package:appflowy_editor/src/flutter/overlay.dart';
import 'package:appflowy_editor/src/infra/clipboard.dart';
import 'package:appflowy_editor/src/infra/flowy_svg.dart';
import 'package:appflowy_editor/src/render/color_menu/color_picker.dart';
import 'package:appflowy_editor/src/render/link_menu/link_menu.dart';
import 'package:appflowy_editor/src/extensions/text_node_extensions.dart';
import 'package:appflowy_editor/src/extensions/editor_state_extensions.dart';
import 'package:appflowy_editor/src/service/default_text_operations/format_rich_text_style.dart';
import 'package:flutter/foundation.dart';
import 'dart:io' show Platform;

View file

@ -22,7 +22,9 @@ class ToolbarWidget extends StatefulWidget {
final EditorState editorState;
final LayerLink layerLink;
final Offset offset;
final List<ToolbarItem> items;
final Alignment alignment;
@override
@ -56,7 +58,8 @@ class _ToolbarWidgetState extends State<ToolbarWidget> with ToolbarMixin {
Widget _buildToolbar(BuildContext context) {
return Material(
borderRadius: BorderRadius.circular(8.0),
color: const Color(0xFF333333),
color: widget.editorState.editorStyle.toolbarColor,
elevation: widget.editorState.editorStyle.toolbarElevation,
child: Padding(
padding: const EdgeInsets.only(left: 8.0, right: 8.0),
child: SizedBox(

View file

@ -1,5 +1,4 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor/src/extensions/text_node_extensions.dart';
void insertHeadingAfterSelection(EditorState editorState, String heading) {
insertTextNodeAfterSelection(editorState, {

View file

@ -34,6 +34,7 @@ class AppFlowyEditor extends StatefulWidget {
this.autoFocus = false,
this.focusedSelection,
this.customActionMenuBuilder,
this.showDefaultToolbar = true,
this.shrinkWrap = false,
ThemeData? themeData,
}) : super(key: key) {
@ -53,7 +54,7 @@ class AppFlowyEditor extends StatefulWidget {
/// Keyboard event handlers.
final List<ShortcutEvent> shortcutEvents;
final bool showDefaultToolbar;
final List<SelectionMenuItem> selectionMenuItems;
final List<ToolbarItem> toolbarItems;
@ -170,6 +171,7 @@ class _AppFlowyEditorState extends State<AppFlowyEditor> {
],
editorState: editorState,
child: FlowyToolbar(
showDefaultToolbar: widget.showDefaultToolbar,
key: editorState.service.toolbarServiceKey,
editorState: editorState,
child:

View file

@ -1,6 +1,5 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor/src/infra/clipboard.dart';
import 'package:appflowy_editor/src/infra/html_converter.dart';
import 'package:appflowy_editor/src/service/internal_key_event_handlers/number_list_helper.dart';
import 'package:flutter/material.dart';

View file

@ -1,6 +1,4 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor/src/extensions/text_node_extensions.dart';
import 'package:appflowy_editor/src/service/default_text_operations/format_rich_text_style.dart';
import 'package:flutter/material.dart';

View file

@ -3,7 +3,6 @@ import 'package:flutter/material.dart' hide Overlay, OverlayEntry;
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor/src/render/toolbar/toolbar_widget.dart';
import 'package:appflowy_editor/src/extensions/object_extensions.dart';
abstract class AppFlowyToolbarService {
/// Show the toolbar widget beside the offset.
@ -25,8 +24,9 @@ class FlowyToolbar extends StatefulWidget {
Key? key,
required this.editorState,
required this.child,
required this.showDefaultToolbar,
}) : super(key: key);
final bool showDefaultToolbar;
final EditorState editorState;
final Widget child;
@ -44,7 +44,9 @@ class _FlowyToolbarState extends State<FlowyToolbar>
void initState() {
super.initState();
toolbarItems = [...defaultToolbarItems, ...widget.editorState.toolbarItems]
toolbarItems = widget.showDefaultToolbar
? [...defaultToolbarItems, ...widget.editorState.toolbarItems]
: [...widget.editorState.toolbarItems]
..sort((a, b) => a.type.compareTo(b.type));
}

View file

@ -1,5 +1,6 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter_test/flutter_test.dart';
import '../infra/test_editor.dart';
void main() {

View file

@ -1,6 +1,5 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter_test/flutter_test.dart';
import '../infra/test_editor.dart';
void main() {

View file

@ -2,8 +2,8 @@ import 'dart:collection';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter_test/flutter_test.dart';
import '../infra/test_editor.dart';
import 'package:mockito/mockito.dart';
import '../infra/test_editor.dart';
class MockNode extends Mock implements Node {}

View file

@ -2,7 +2,6 @@ import 'package:appflowy_editor/src/infra/flowy_svg.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:flutter_test/flutter_test.dart';
import '../test_helper.dart';
void main() {

View file

@ -25,6 +25,14 @@ void main() {
expect(html.isNotEmpty, true);
});
});
group('HTMLConverterDocument tests', () {
test('HTMLToNodesConverter', () {
final converter = HTMLToNodesConverter(rawHTML);
final document = converter.toDocument();
expect(document.root.children.isNotEmpty, true);
});
});
}
const rawHTML = """<h1>AppFlowyEditor</h1>

View file

@ -1,8 +1,6 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor/src/infra/flowy_svg.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import '../../test_helper.dart';
void main() {

Some files were not shown because too many files have changed in this diff Show more