diff --git a/example/lib/pages/customize_theme_for_editor.dart b/example/lib/pages/customize_theme_for_editor.dart index 273ea7283..b87b977fd 100644 --- a/example/lib/pages/customize_theme_for_editor.dart +++ b/example/lib/pages/customize_theme_for_editor.dart @@ -102,7 +102,7 @@ class _CustomizeThemeForEditorState extends State { // todo-list block TodoListBlockKeys.type: TodoListBlockComponentBuilder( configuration: configuration, - iconBuilder: (context, node) { + iconBuilder: (context, node, ___) { final checked = node.attributes[TodoListBlockKeys.checked] as bool; return GestureDetector( onTap: () => editorState.apply( diff --git a/lib/src/editor/block_component/base_component/text_style_configuration.dart b/lib/src/editor/block_component/base_component/text_style_configuration.dart index 7297e5ded..29736f287 100644 --- a/lib/src/editor/block_component/base_component/text_style_configuration.dart +++ b/lib/src/editor/block_component/base_component/text_style_configuration.dart @@ -23,6 +23,8 @@ class TextStyleConfiguration { this.autoComplete = const TextStyle( color: Colors.grey, ), + this.applyHeightToFirstAscent = false, + this.applyHeightToLastDescent = false, }); /// default text style @@ -49,6 +51,10 @@ class TextStyleConfiguration { /// auto complete text style final TextStyle autoComplete; + /// apply line height to the first or the last ascent + final bool applyHeightToFirstAscent; + final bool applyHeightToLastDescent; + TextStyleConfiguration copyWith({ TextStyle? text, TextStyle? bold, @@ -58,6 +64,8 @@ class TextStyleConfiguration { TextStyle? href, TextStyle? code, TextStyle? autoComplete, + bool? applyHeightToFirstAscent, + bool? applyHeightToLastDescent, }) { return TextStyleConfiguration( text: text ?? this.text, @@ -68,6 +76,10 @@ class TextStyleConfiguration { href: href ?? this.href, code: code ?? this.code, autoComplete: autoComplete ?? this.autoComplete, + applyHeightToFirstAscent: + applyHeightToFirstAscent ?? this.applyHeightToFirstAscent, + applyHeightToLastDescent: + applyHeightToLastDescent ?? this.applyHeightToLastDescent, ); } } diff --git a/lib/src/editor/block_component/numbered_list_block_component/numbered_list_block_component.dart b/lib/src/editor/block_component/numbered_list_block_component/numbered_list_block_component.dart index 309f41611..2a0b2598d 100644 --- a/lib/src/editor/block_component/numbered_list_block_component/numbered_list_block_component.dart +++ b/lib/src/editor/block_component/numbered_list_block_component/numbered_list_block_component.dart @@ -1,5 +1,4 @@ import 'package:appflowy_editor/appflowy_editor.dart'; -import 'package:appflowy_editor/src/editor/block_component/base_component/block_icon_builder.dart'; import 'package:flutter/material.dart'; import 'package:numerus/roman/roman.dart'; import 'package:provider/provider.dart'; @@ -40,13 +39,19 @@ Node numberedListNode({ ); } +typedef NumberedListIconBuilder = Widget Function( + BuildContext context, + Node node, + TextDirection direction, +); + class NumberedListBlockComponentBuilder extends BlockComponentBuilder { NumberedListBlockComponentBuilder({ super.configuration, this.iconBuilder, }); - final BlockIconBuilder? iconBuilder; + final NumberedListIconBuilder? iconBuilder; @override BlockComponentWidget build(BlockComponentContext blockComponentContext) { @@ -78,7 +83,7 @@ class NumberedListBlockComponentWidget extends BlockComponentStatefulWidget { this.iconBuilder, }); - final BlockIconBuilder? iconBuilder; + final NumberedListIconBuilder? iconBuilder; @override State createState() => @@ -131,7 +136,11 @@ class _NumberedListBlockComponentWidgetState textDirection: textDirection, children: [ widget.iconBuilder != null - ? widget.iconBuilder!(context, node) + ? widget.iconBuilder!( + context, + node, + textDirection, + ) : _NumberedListIcon( node: node, textStyle: textStyle, diff --git a/lib/src/editor/block_component/rich_text/appflowy_rich_text.dart b/lib/src/editor/block_component/rich_text/appflowy_rich_text.dart index 25d6442d2..7edb7b936 100644 --- a/lib/src/editor/block_component/rich_text/appflowy_rich_text.dart +++ b/lib/src/editor/block_component/rich_text/appflowy_rich_text.dart @@ -1,18 +1,7 @@ import 'dart:math'; import 'dart:ui'; -import 'package:appflowy_editor/src/core/document/attributes.dart'; -import 'package:appflowy_editor/src/core/document/node.dart'; -import 'package:appflowy_editor/src/core/document/path.dart'; -import 'package:appflowy_editor/src/core/document/text_delta.dart'; -import 'package:appflowy_editor/src/core/location/position.dart'; -import 'package:appflowy_editor/src/core/location/selection.dart'; -import 'package:appflowy_editor/src/editor/block_component/base_component/selection/block_selection_container.dart'; -import 'package:appflowy_editor/src/editor/block_component/rich_text/appflowy_rich_text_keys.dart'; -import 'package:appflowy_editor/src/editor/util/color_util.dart'; -import 'package:appflowy_editor/src/editor_state.dart'; -import 'package:appflowy_editor/src/extensions/text_style_extension.dart'; -import 'package:appflowy_editor/src/render/selection/selectable.dart'; +import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; @@ -122,6 +111,9 @@ class _AppFlowyRichTextState extends State bool get enableAutoComplete => widget.editorState.enableAutoComplete && autoCompleteTextProvider != null; + TextStyleConfiguration get textStyleConfiguration => + widget.editorState.editorStyle.textStyleConfiguration; + @override Widget build(BuildContext context) { Widget child = _buildRichText(context); @@ -328,9 +320,11 @@ class _AppFlowyRichTextState extends State final textSpan = getPlaceholderTextSpan(); return RichText( key: placeholderTextKey, - textHeightBehavior: const TextHeightBehavior( - applyHeightToFirstAscent: false, - applyHeightToLastDescent: false, + textHeightBehavior: TextHeightBehavior( + applyHeightToFirstAscent: + textStyleConfiguration.applyHeightToFirstAscent, + applyHeightToLastDescent: + textStyleConfiguration.applyHeightToLastDescent, ), text: widget.placeholderTextSpanDecorator != null ? widget.placeholderTextSpanDecorator!(textSpan) @@ -347,9 +341,11 @@ class _AppFlowyRichTextState extends State return RichText( key: textKey, textAlign: widget.textAlign ?? TextAlign.start, - textHeightBehavior: const TextHeightBehavior( - applyHeightToFirstAscent: false, - applyHeightToLastDescent: false, + textHeightBehavior: TextHeightBehavior( + applyHeightToFirstAscent: + textStyleConfiguration.applyHeightToFirstAscent, + applyHeightToLastDescent: + textStyleConfiguration.applyHeightToLastDescent, ), text: widget.textSpanDecorator != null ? widget.textSpanDecorator!(textSpan) @@ -394,9 +390,11 @@ class _AppFlowyRichTextState extends State ); return RichText( textAlign: widget.textAlign ?? TextAlign.start, - textHeightBehavior: const TextHeightBehavior( - applyHeightToFirstAscent: false, - applyHeightToLastDescent: false, + textHeightBehavior: TextHeightBehavior( + applyHeightToFirstAscent: + textStyleConfiguration.applyHeightToFirstAscent, + applyHeightToLastDescent: + textStyleConfiguration.applyHeightToLastDescent, ), text: widget.textSpanDecorator != null ? widget.textSpanDecorator!(textSpan) @@ -410,12 +408,13 @@ class _AppFlowyRichTextState extends State } TextSpan getPlaceholderTextSpan() { - final style = widget.editorState.editorStyle.textStyleConfiguration; return TextSpan( children: [ TextSpan( text: widget.placeholderText, - style: style.text.copyWith(height: widget.lineHeight), + style: textStyleConfiguration.text.copyWith( + height: widget.lineHeight, + ), ), ], ); @@ -426,28 +425,28 @@ class _AppFlowyRichTextState extends State }) { int offset = 0; List textSpans = []; - final style = widget.editorState.editorStyle.textStyleConfiguration; for (final textInsert in textInserts) { - TextStyle textStyle = style.text.copyWith(height: widget.lineHeight); + TextStyle textStyle = + textStyleConfiguration.text.copyWith(height: widget.lineHeight); final attributes = textInsert.attributes; if (attributes != null) { if (attributes.bold == true) { - textStyle = textStyle.combine(style.bold); + textStyle = textStyle.combine(textStyleConfiguration.bold); } if (attributes.italic == true) { - textStyle = textStyle.combine(style.italic); + textStyle = textStyle.combine(textStyleConfiguration.italic); } if (attributes.underline == true) { - textStyle = textStyle.combine(style.underline); + textStyle = textStyle.combine(textStyleConfiguration.underline); } if (attributes.strikethrough == true) { - textStyle = textStyle.combine(style.strikethrough); + textStyle = textStyle.combine(textStyleConfiguration.strikethrough); } if (attributes.href != null) { - textStyle = textStyle.combine(style.href); + textStyle = textStyle.combine(textStyleConfiguration.href); } if (attributes.code == true) { - textStyle = textStyle.combine(style.code); + textStyle = textStyle.combine(textStyleConfiguration.code); } if (attributes.backgroundColor != null) { textStyle = textStyle.combine( @@ -475,7 +474,7 @@ class _AppFlowyRichTextState extends State ); } if (attributes.autoComplete == true) { - textStyle = textStyle.combine(style.autoComplete); + textStyle = textStyle.combine(textStyleConfiguration.autoComplete); } if (attributes.transparent == true) { textStyle = textStyle.combine( diff --git a/lib/src/editor/block_component/todo_list_block_component/todo_list_block_component.dart b/lib/src/editor/block_component/todo_list_block_component/todo_list_block_component.dart index 4138ff33b..829fdfc9f 100644 --- a/lib/src/editor/block_component/todo_list_block_component/todo_list_block_component.dart +++ b/lib/src/editor/block_component/todo_list_block_component/todo_list_block_component.dart @@ -1,5 +1,4 @@ import 'package:appflowy_editor/appflowy_editor.dart'; -import 'package:appflowy_editor/src/editor/block_component/base_component/block_icon_builder.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; @@ -42,6 +41,12 @@ Node todoListNode({ ); } +typedef TodoListIconBuilder = Widget Function( + BuildContext context, + Node node, + VoidCallback onCheck, +); + class TodoListBlockComponentBuilder extends BlockComponentBuilder { TodoListBlockComponentBuilder({ super.configuration, @@ -53,7 +58,7 @@ class TodoListBlockComponentBuilder extends BlockComponentBuilder { /// The text style of the todo list block. final TextStyle Function(bool checked)? textStyleBuilder; - final BlockIconBuilder? iconBuilder; + final TodoListIconBuilder? iconBuilder; final List? toggleChildrenTriggers; @@ -95,7 +100,7 @@ class TodoListBlockComponentWidget extends BlockComponentStatefulWidget { }); final TextStyle Function(bool checked)? textStyleBuilder; - final BlockIconBuilder? iconBuilder; + final TodoListIconBuilder? iconBuilder; final List? toggleChildrenTriggers; @override @@ -151,7 +156,11 @@ class _TodoListBlockComponentWidgetState textDirection: textDirection, children: [ widget.iconBuilder != null - ? widget.iconBuilder!(context, node) + ? widget.iconBuilder!( + context, + node, + checkOrUncheck, + ) : _TodoListIcon( checked: checked, onTap: checkOrUncheck, diff --git a/test/customer/custom_block_icon_test.dart b/test/customer/custom_block_icon_test.dart index ea9e9be70..2298ed1f0 100644 --- a/test/customer/custom_block_icon_test.dart +++ b/test/customer/custom_block_icon_test.dart @@ -58,10 +58,10 @@ class CustomBlockIcon extends StatelessWidget { iconBuilder: (_, __) => Icon(iconMap[BulletedListBlockKeys.type]), ), NumberedListBlockKeys.type: NumberedListBlockComponentBuilder( - iconBuilder: (_, __) => Icon(iconMap[NumberedListBlockKeys.type]), + iconBuilder: (_, __, ___) => Icon(iconMap[NumberedListBlockKeys.type]), ), TodoListBlockKeys.type: TodoListBlockComponentBuilder( - iconBuilder: (_, __) => Icon(iconMap[TodoListBlockKeys.type]), + iconBuilder: (_, __, ___) => Icon(iconMap[TodoListBlockKeys.type]), ), QuoteBlockKeys.type: QuoteBlockComponentBuilder( iconBuilder: (_, __) => Icon(iconMap[QuoteBlockKeys.type]),