diff --git a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/bulleted_list_text.dart b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/bulleted_list_text.dart index 0eae3f22f2..fcba91c3c9 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/bulleted_list_text.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/bulleted_list_text.dart @@ -64,6 +64,7 @@ class _BulletedListTextNodeWidgetState extends State ), FlowyRichText( key: _richTextKey, + placeholderText: 'List', textNode: widget.textNode, editorState: widget.editorState, ), diff --git a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/checkbox_text.dart b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/checkbox_text.dart index ba2c5b8712..d6eeb65c3d 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/checkbox_text.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/checkbox_text.dart @@ -84,6 +84,7 @@ class _CheckboxNodeWidgetState extends State ), FlowyRichText( key: _richTextKey, + placeholderText: 'To-do', textNode: widget.textNode, editorState: widget.editorState, ) diff --git a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/flowy_rich_text.dart b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/flowy_rich_text.dart index 83d809745c..f7b79342b8 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/flowy_rich_text.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/flowy_rich_text.dart @@ -35,15 +35,19 @@ class FlowyRichText extends StatefulWidget { this.cursorHeight, this.cursorWidth = 2.0, this.textSpanDecorator, + this.placeholderText = ' ', + this.placeholderTextSpanDecorator, required this.textNode, required this.editorState, }) : super(key: key); - final double? cursorHeight; - final double cursorWidth; final TextNode textNode; final EditorState editorState; + final double? cursorHeight; + final double cursorWidth; final FlowyTextSpanDecorator? textSpanDecorator; + final String placeholderText; + final FlowyTextSpanDecorator? placeholderTextSpanDecorator; @override State createState() => _FlowyRichTextState(); @@ -51,10 +55,14 @@ class FlowyRichText extends StatefulWidget { class _FlowyRichTextState extends State with Selectable { final _textKey = GlobalKey(); + final _placeholderTextKey = GlobalKey(); RenderParagraph get _renderParagraph => _textKey.currentContext?.findRenderObject() as RenderParagraph; + RenderParagraph get _placeholderRenderParagraph => + _placeholderTextKey.currentContext?.findRenderObject() as RenderParagraph; + @override Widget build(BuildContext context) { return _buildRichText(context); @@ -74,6 +82,7 @@ class _FlowyRichTextState extends State with Selectable { _renderParagraph.getOffsetForCaret(textPosition, Rect.zero); final cursorHeight = widget.cursorHeight ?? _renderParagraph.getFullHeightForCaret(textPosition) ?? + _placeholderRenderParagraph.getFullHeightForCaret(textPosition) ?? 18.0; // default height return Rect.fromLTWH( cursorOffset.dx - (widget.cursorWidth / 2), @@ -129,9 +138,35 @@ class _FlowyRichTextState extends State with Selectable { } Widget _buildRichText(BuildContext context) { - return Align( - alignment: Alignment.centerLeft, - child: _buildSingleRichText(context), + return Stack( + children: [ + _buildPlaceholderText(context), + Align( + alignment: Alignment.centerLeft, + child: _buildSingleRichText(context), + ) + ], + ); + } + + Widget _buildPlaceholderText(BuildContext context) { + final textSpan = TextSpan( + children: [ + TextSpan( + text: widget.placeholderText, + style: TextStyle( + color: widget.textNode.toRawString().isNotEmpty + ? Colors.transparent + : Colors.grey, + ), + ), + ], + ); + return RichText( + key: _placeholderTextKey, + text: widget.placeholderTextSpanDecorator != null + ? widget.placeholderTextSpanDecorator!(textSpan) + : textSpan, ); } diff --git a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/heading_text.dart b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/heading_text.dart index 4990e90dcf..aacdd9f903 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/heading_text.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/heading_text.dart @@ -65,6 +65,8 @@ class _HeadingTextNodeWidgetState extends State ), child: FlowyRichText( key: _richTextKey, + placeholderText: 'Heading', + placeholderTextSpanDecorator: _placeholderTextSpanDecorator, textSpanDecorator: _textSpanDecorator, textNode: widget.textNode, editorState: widget.editorState, @@ -90,4 +92,21 @@ class _HeadingTextNodeWidgetState extends State .toList(), ); } + + TextSpan _placeholderTextSpanDecorator(TextSpan textSpan) { + return TextSpan( + children: textSpan.children + ?.whereType() + .map( + (span) => TextSpan( + text: span.text, + style: span.style?.copyWith( + fontSize: widget.textNode.attributes.fontSize, + ), + recognizer: span.recognizer, + ), + ) + .toList(), + ); + } } diff --git a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/number_list_text.dart b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/number_list_text.dart index 1c52b93d4b..12d95f8c9a 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/number_list_text.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/number_list_text.dart @@ -65,6 +65,7 @@ class _NumberListTextNodeWidgetState extends State ), FlowyRichText( key: _richTextKey, + placeholderText: 'List', textNode: widget.textNode, editorState: widget.editorState, ), diff --git a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/quoted_text.dart b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/quoted_text.dart index 41520c560f..e2a43058c8 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/quoted_text.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/quoted_text.dart @@ -64,6 +64,7 @@ class _QuotedTextNodeWidgetState extends State ), FlowyRichText( key: _richTextKey, + placeholderText: 'Quote', textNode: widget.textNode, editorState: widget.editorState, ),