feat: expose text span for text style builder (#1011)
* feat: expose textspan for text style builder * fix: content menu will show when collaborating
This commit is contained in:
parent
9f6a29968e
commit
2490f698c3
10 changed files with 47 additions and 31 deletions
|
|
@ -85,7 +85,7 @@ class _CustomizeThemeForEditorState extends State<CustomizeThemeForEditor> {
|
||||||
}
|
}
|
||||||
return const EdgeInsets.symmetric(vertical: 5);
|
return const EdgeInsets.symmetric(vertical: 5);
|
||||||
},
|
},
|
||||||
textStyle: (node) {
|
textStyle: (node, {TextSpan? textSpan}) {
|
||||||
if (HeadingBlockKeys.type == node.type) {
|
if (HeadingBlockKeys.type == node.type) {
|
||||||
return const TextStyle(color: Colors.yellow);
|
return const TextStyle(color: Colors.yellow);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
typedef BlockComponentTextStyleBuilder = TextStyle Function(
|
||||||
|
Node node, {
|
||||||
|
TextSpan? textSpan,
|
||||||
|
});
|
||||||
|
|
||||||
/// only for the common config of block component
|
/// only for the common config of block component
|
||||||
class BlockComponentConfiguration {
|
class BlockComponentConfiguration {
|
||||||
const BlockComponentConfiguration({
|
const BlockComponentConfiguration({
|
||||||
|
|
@ -27,7 +32,7 @@ class BlockComponentConfiguration {
|
||||||
) indentPadding;
|
) indentPadding;
|
||||||
|
|
||||||
/// The text style of a block component.
|
/// The text style of a block component.
|
||||||
final TextStyle Function(Node node) textStyle;
|
final BlockComponentTextStyleBuilder textStyle;
|
||||||
|
|
||||||
/// The placeholder text of a block component.
|
/// The placeholder text of a block component.
|
||||||
final String Function(Node node) placeholderText;
|
final String Function(Node node) placeholderText;
|
||||||
|
|
@ -35,7 +40,7 @@ class BlockComponentConfiguration {
|
||||||
/// The placeholder text style of a block component.
|
/// The placeholder text style of a block component.
|
||||||
///
|
///
|
||||||
/// It inherits the style from [textStyle].
|
/// It inherits the style from [textStyle].
|
||||||
final TextStyle Function(Node node) placeholderTextStyle;
|
final BlockComponentTextStyleBuilder placeholderTextStyle;
|
||||||
|
|
||||||
/// The padding of a block selection area.
|
/// The padding of a block selection area.
|
||||||
final EdgeInsets Function(Node node) blockSelectionAreaMargin;
|
final EdgeInsets Function(Node node) blockSelectionAreaMargin;
|
||||||
|
|
@ -48,9 +53,9 @@ class BlockComponentConfiguration {
|
||||||
|
|
||||||
BlockComponentConfiguration copyWith({
|
BlockComponentConfiguration copyWith({
|
||||||
EdgeInsets Function(Node node)? padding,
|
EdgeInsets Function(Node node)? padding,
|
||||||
TextStyle Function(Node node)? textStyle,
|
BlockComponentTextStyleBuilder? textStyle,
|
||||||
String Function(Node node)? placeholderText,
|
String Function(Node node)? placeholderText,
|
||||||
TextStyle Function(Node node)? placeholderTextStyle,
|
BlockComponentTextStyleBuilder? placeholderTextStyle,
|
||||||
EdgeInsets Function(Node node)? blockSelectionAreaMargin,
|
EdgeInsets Function(Node node)? blockSelectionAreaMargin,
|
||||||
TextAlign Function(Node node)? textAlign,
|
TextAlign Function(Node node)? textAlign,
|
||||||
}) {
|
}) {
|
||||||
|
|
@ -72,13 +77,14 @@ mixin BlockComponentConfigurable<T extends StatefulWidget> on State<T> {
|
||||||
|
|
||||||
EdgeInsets get padding => configuration.padding(node);
|
EdgeInsets get padding => configuration.padding(node);
|
||||||
|
|
||||||
TextStyle get textStyle => configuration.textStyle(node);
|
TextStyle textStyleWithTextSpan({TextSpan? textSpan}) =>
|
||||||
|
configuration.textStyle(node, textSpan: textSpan);
|
||||||
|
|
||||||
|
TextStyle placeholderTextStyleWithTextSpan({TextSpan? textSpan}) =>
|
||||||
|
configuration.placeholderTextStyle(node, textSpan: textSpan);
|
||||||
|
|
||||||
String get placeholderText => configuration.placeholderText(node);
|
String get placeholderText => configuration.placeholderText(node);
|
||||||
|
|
||||||
TextStyle get placeholderTextStyle =>
|
|
||||||
configuration.placeholderTextStyle(node);
|
|
||||||
|
|
||||||
TextAlign get textAlign => configuration.textAlign(node);
|
TextAlign get textAlign => configuration.textAlign(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,7 +101,7 @@ EdgeInsets _indentPadding(Node node, TextDirection textDirection) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TextStyle _textStyle(Node node) {
|
TextStyle _textStyle(Node node, {TextSpan? textSpan}) {
|
||||||
return const TextStyle();
|
return const TextStyle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -103,7 +109,7 @@ String _placeholderText(Node node) {
|
||||||
return ' ';
|
return ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
TextStyle _placeholderTextStyle(Node node) {
|
TextStyle _placeholderTextStyle(Node node, {TextSpan? textSpan}) {
|
||||||
return const TextStyle(
|
return const TextStyle(
|
||||||
color: Colors.grey,
|
color: Colors.grey,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -129,7 +129,7 @@ class _BulletedListBlockComponentWidgetState
|
||||||
? widget.iconBuilder!(context, node)
|
? widget.iconBuilder!(context, node)
|
||||||
: _BulletedListIcon(
|
: _BulletedListIcon(
|
||||||
node: widget.node,
|
node: widget.node,
|
||||||
textStyle: textStyle,
|
textStyle: textStyleWithTextSpan(),
|
||||||
),
|
),
|
||||||
Flexible(
|
Flexible(
|
||||||
child: AppFlowyRichText(
|
child: AppFlowyRichText(
|
||||||
|
|
@ -140,11 +140,11 @@ class _BulletedListBlockComponentWidgetState
|
||||||
textAlign: alignment?.toTextAlign ?? textAlign,
|
textAlign: alignment?.toTextAlign ?? textAlign,
|
||||||
placeholderText: placeholderText,
|
placeholderText: placeholderText,
|
||||||
textSpanDecorator: (textSpan) => textSpan.updateTextStyle(
|
textSpanDecorator: (textSpan) => textSpan.updateTextStyle(
|
||||||
textStyle,
|
textStyleWithTextSpan(textSpan: textSpan),
|
||||||
),
|
),
|
||||||
placeholderTextSpanDecorator: (textSpan) =>
|
placeholderTextSpanDecorator: (textSpan) =>
|
||||||
textSpan.updateTextStyle(
|
textSpan.updateTextStyle(
|
||||||
placeholderTextStyle,
|
placeholderTextStyleWithTextSpan(textSpan: textSpan),
|
||||||
),
|
),
|
||||||
textDirection: textDirection,
|
textDirection: textDirection,
|
||||||
cursorColor: editorState.editorStyle.cursorColor,
|
cursorColor: editorState.editorStyle.cursorColor,
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,9 @@ class _HeadingBlockComponentWidgetState
|
||||||
editorState: editorState,
|
editorState: editorState,
|
||||||
textAlign: alignment?.toTextAlign ?? textAlign,
|
textAlign: alignment?.toTextAlign ?? textAlign,
|
||||||
textSpanDecorator: (textSpan) {
|
textSpanDecorator: (textSpan) {
|
||||||
var result = textSpan.updateTextStyle(textStyle);
|
var result = textSpan.updateTextStyle(
|
||||||
|
textStyleWithTextSpan(textSpan: textSpan),
|
||||||
|
);
|
||||||
result = result.updateTextStyle(
|
result = result.updateTextStyle(
|
||||||
widget.textStyleBuilder?.call(level) ??
|
widget.textStyleBuilder?.call(level) ??
|
||||||
defaultTextStyle(level),
|
defaultTextStyle(level),
|
||||||
|
|
@ -153,7 +155,7 @@ class _HeadingBlockComponentWidgetState
|
||||||
defaultTextStyle(level),
|
defaultTextStyle(level),
|
||||||
)
|
)
|
||||||
.updateTextStyle(
|
.updateTextStyle(
|
||||||
placeholderTextStyle,
|
placeholderTextStyleWithTextSpan(textSpan: textSpan),
|
||||||
),
|
),
|
||||||
textDirection: textDirection,
|
textDirection: textDirection,
|
||||||
cursorColor: editorState.editorStyle.cursorColor,
|
cursorColor: editorState.editorStyle.cursorColor,
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,7 @@ class _NumberedListBlockComponentWidgetState
|
||||||
)
|
)
|
||||||
: _NumberedListIcon(
|
: _NumberedListIcon(
|
||||||
node: node,
|
node: node,
|
||||||
textStyle: textStyle,
|
textStyle: textStyleWithTextSpan(),
|
||||||
direction: textDirection,
|
direction: textDirection,
|
||||||
),
|
),
|
||||||
Flexible(
|
Flexible(
|
||||||
|
|
@ -155,11 +155,11 @@ class _NumberedListBlockComponentWidgetState
|
||||||
textAlign: alignment?.toTextAlign ?? textAlign,
|
textAlign: alignment?.toTextAlign ?? textAlign,
|
||||||
placeholderText: placeholderText,
|
placeholderText: placeholderText,
|
||||||
textSpanDecorator: (textSpan) => textSpan.updateTextStyle(
|
textSpanDecorator: (textSpan) => textSpan.updateTextStyle(
|
||||||
textStyle,
|
textStyleWithTextSpan(textSpan: textSpan),
|
||||||
),
|
),
|
||||||
placeholderTextSpanDecorator: (textSpan) =>
|
placeholderTextSpanDecorator: (textSpan) =>
|
||||||
textSpan.updateTextStyle(
|
textSpan.updateTextStyle(
|
||||||
placeholderTextStyle,
|
placeholderTextStyleWithTextSpan(textSpan: textSpan),
|
||||||
),
|
),
|
||||||
textDirection: textDirection,
|
textDirection: textDirection,
|
||||||
cursorColor: editorState.editorStyle.cursorColor,
|
cursorColor: editorState.editorStyle.cursorColor,
|
||||||
|
|
|
||||||
|
|
@ -163,10 +163,15 @@ class _ParagraphBlockComponentWidgetState
|
||||||
editorState: editorState,
|
editorState: editorState,
|
||||||
textAlign: alignment?.toTextAlign ?? textAlign,
|
textAlign: alignment?.toTextAlign ?? textAlign,
|
||||||
placeholderText: _showPlaceholder ? placeholderText : ' ',
|
placeholderText: _showPlaceholder ? placeholderText : ' ',
|
||||||
textSpanDecorator: (textSpan) =>
|
textSpanDecorator: (textSpan) => textSpan.updateTextStyle(
|
||||||
textSpan.updateTextStyle(textStyle),
|
textStyleWithTextSpan(
|
||||||
|
textSpan: textSpan,
|
||||||
|
),
|
||||||
|
),
|
||||||
placeholderTextSpanDecorator: (textSpan) =>
|
placeholderTextSpanDecorator: (textSpan) =>
|
||||||
textSpan.updateTextStyle(placeholderTextStyle),
|
textSpan.updateTextStyle(
|
||||||
|
placeholderTextStyleWithTextSpan(textSpan: textSpan),
|
||||||
|
),
|
||||||
textDirection: textDirection,
|
textDirection: textDirection,
|
||||||
cursorColor: editorState.editorStyle.cursorColor,
|
cursorColor: editorState.editorStyle.cursorColor,
|
||||||
selectionColor: editorState.editorStyle.selectionColor,
|
selectionColor: editorState.editorStyle.selectionColor,
|
||||||
|
|
|
||||||
|
|
@ -133,11 +133,11 @@ class _QuoteBlockComponentWidgetState extends State<QuoteBlockComponentWidget>
|
||||||
textAlign: alignment?.toTextAlign ?? textAlign,
|
textAlign: alignment?.toTextAlign ?? textAlign,
|
||||||
placeholderText: placeholderText,
|
placeholderText: placeholderText,
|
||||||
textSpanDecorator: (textSpan) => textSpan.updateTextStyle(
|
textSpanDecorator: (textSpan) => textSpan.updateTextStyle(
|
||||||
textStyle,
|
textStyleWithTextSpan(textSpan: textSpan),
|
||||||
),
|
),
|
||||||
placeholderTextSpanDecorator: (textSpan) =>
|
placeholderTextSpanDecorator: (textSpan) =>
|
||||||
textSpan.updateTextStyle(
|
textSpan.updateTextStyle(
|
||||||
placeholderTextStyle,
|
placeholderTextStyleWithTextSpan(textSpan: textSpan),
|
||||||
),
|
),
|
||||||
textDirection: textDirection,
|
textDirection: textDirection,
|
||||||
cursorColor: editorState.editorStyle.cursorColor,
|
cursorColor: editorState.editorStyle.cursorColor,
|
||||||
|
|
|
||||||
|
|
@ -172,14 +172,15 @@ class _TodoListBlockComponentWidgetState
|
||||||
textAlign: alignment?.toTextAlign ?? textAlign,
|
textAlign: alignment?.toTextAlign ?? textAlign,
|
||||||
placeholderText: placeholderText,
|
placeholderText: placeholderText,
|
||||||
textDirection: textDirection,
|
textDirection: textDirection,
|
||||||
textSpanDecorator: (textSpan) =>
|
textSpanDecorator: (textSpan) => textSpan
|
||||||
textSpan.updateTextStyle(textStyle).updateTextStyle(
|
.updateTextStyle(textStyleWithTextSpan())
|
||||||
widget.textStyleBuilder?.call(checked) ??
|
.updateTextStyle(
|
||||||
defaultTextStyle(),
|
widget.textStyleBuilder?.call(checked) ??
|
||||||
),
|
defaultTextStyle(),
|
||||||
|
),
|
||||||
placeholderTextSpanDecorator: (textSpan) =>
|
placeholderTextSpanDecorator: (textSpan) =>
|
||||||
textSpan.updateTextStyle(
|
textSpan.updateTextStyle(
|
||||||
placeholderTextStyle,
|
placeholderTextStyleWithTextSpan(textSpan: textSpan),
|
||||||
),
|
),
|
||||||
cursorColor: editorState.editorStyle.cursorColor,
|
cursorColor: editorState.editorStyle.cursorColor,
|
||||||
selectionColor: editorState.editorStyle.selectionColor,
|
selectionColor: editorState.editorStyle.selectionColor,
|
||||||
|
|
|
||||||
|
|
@ -204,7 +204,7 @@ class SelectionMenu extends SelectionMenuService {
|
||||||
// Workaround: We can customize the padding through the [EditorStyle],
|
// Workaround: We can customize the padding through the [EditorStyle],
|
||||||
// but the coordinates of overlay are not properly converted currently.
|
// but the coordinates of overlay are not properly converted currently.
|
||||||
// Just subtract the padding here as a result.
|
// Just subtract the padding here as a result.
|
||||||
const menuHeight = 200.0;
|
const menuHeight = 300.0;
|
||||||
const menuOffset = Offset(0, 10);
|
const menuOffset = Offset(0, 10);
|
||||||
final editorOffset =
|
final editorOffset =
|
||||||
editorState.renderBox?.localToGlobal(Offset.zero) ?? Offset.zero;
|
editorState.renderBox?.localToGlobal(Offset.zero) ?? Offset.zero;
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ enum CursorUpdateReason {
|
||||||
enum SelectionUpdateReason {
|
enum SelectionUpdateReason {
|
||||||
uiEvent, // like mouse click, keyboard event
|
uiEvent, // like mouse click, keyboard event
|
||||||
transaction, // like insert, delete, format
|
transaction, // like insert, delete, format
|
||||||
|
remote, // like remote selection
|
||||||
selectAll,
|
selectAll,
|
||||||
searchHighlight, // Highlighting search results
|
searchHighlight, // Highlighting search results
|
||||||
}
|
}
|
||||||
|
|
@ -359,6 +360,7 @@ class EditorState {
|
||||||
final completer = Completer<void>();
|
final completer = Completer<void>();
|
||||||
|
|
||||||
if (isRemote) {
|
if (isRemote) {
|
||||||
|
_selectionUpdateReason = SelectionUpdateReason.remote;
|
||||||
selection = _applyTransactionFromRemote(transaction);
|
selection = _applyTransactionFromRemote(transaction);
|
||||||
} else {
|
} else {
|
||||||
// broadcast to other users here, before applying the transaction
|
// broadcast to other users here, before applying the transaction
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue