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 4d52e41867..ba2c5b8712 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 @@ -21,7 +21,7 @@ class CheckboxNodeWidgetBuilder extends NodeWidgetBuilder { @override NodeValidator get nodeValidator => ((node) { - return node.attributes.containsKey(StyleKey.check); + return node.attributes.containsKey(StyleKey.checkbox); }); } diff --git a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/rich_text_style.dart b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/rich_text_style.dart index 26d4275774..19aa109faf 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/rich_text_style.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/render/rich_text/rich_text_style.dart @@ -25,26 +25,48 @@ class StyleKey { static String font = 'font'; static String href = 'href'; - static String quote = 'quote'; - static String list = 'list'; - static String number = 'number'; - static String todo = 'todo'; - static String code = 'code'; - static String subtype = 'subtype'; - static String check = 'checkbox'; static String heading = 'heading'; + static String h1 = 'h1'; + static String h2 = 'h2'; + static String h3 = 'h3'; + static String h4 = 'h4'; + static String h5 = 'h5'; + static String h6 = 'h6'; + + static String bulletedList = 'bulleted-list'; + static String numberList = 'number-list'; + + static String quote = 'quote'; + static String checkbox = 'checkbox'; + static String code = 'code'; + static String number = 'number'; + + static List partialStyleKeys = [ + StyleKey.bold, + StyleKey.italic, + StyleKey.underline, + StyleKey.strikethrough, + ]; + + static List globalStyleKeys = [ + StyleKey.heading, + StyleKey.bulletedList, + StyleKey.numberList, + StyleKey.quote, + StyleKey.code, + ]; } double baseFontSize = 16.0; // TODO: customize. Map headingToFontSize = { - 'h1': baseFontSize + 15, - 'h2': baseFontSize + 12, - 'h3': baseFontSize + 9, - 'h4': baseFontSize + 6, - 'h5': baseFontSize + 3, - 'h6': baseFontSize, + StyleKey.h1: baseFontSize + 15, + StyleKey.h2: baseFontSize + 12, + StyleKey.h3: baseFontSize + 9, + StyleKey.h4: baseFontSize + 6, + StyleKey.h5: baseFontSize + 3, + StyleKey.h6: baseFontSize, }; extension NodeAttributesExtensions on Attributes { @@ -73,13 +95,6 @@ extension NodeAttributesExtensions on Attributes { return null; } - String? get list { - if (containsKey(StyleKey.list) && this[StyleKey.list] is String) { - return this[StyleKey.list]; - } - return null; - } - int? get number { if (containsKey(StyleKey.number) && this[StyleKey.number] is int) { return this[StyleKey.number]; @@ -87,13 +102,6 @@ extension NodeAttributesExtensions on Attributes { return null; } - bool get todo { - if (containsKey(StyleKey.todo) && this[StyleKey.todo] is bool) { - return this[StyleKey.todo]; - } - return false; - } - bool get code { if (containsKey(StyleKey.code) && this[StyleKey.code] == true) { return this[StyleKey.code]; @@ -102,8 +110,8 @@ extension NodeAttributesExtensions on Attributes { } bool get check { - if (containsKey(StyleKey.check) && this[StyleKey.check] is bool) { - return this[StyleKey.check]; + if (containsKey(StyleKey.checkbox) && this[StyleKey.checkbox] is bool) { + return this[StyleKey.checkbox]; } return false; } diff --git a/frontend/app_flowy/packages/flowy_editor/lib/render/selection/toolbar_widget.dart b/frontend/app_flowy/packages/flowy_editor/lib/render/selection/toolbar_widget.dart index 1a05b6ef10..c06776a0a3 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/render/selection/toolbar_widget.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/render/selection/toolbar_widget.dart @@ -1,8 +1,9 @@ +import 'package:flowy_editor/render/rich_text/rich_text_style.dart'; +import 'package:flutter/material.dart'; + import 'package:flowy_editor/editor_state.dart'; import 'package:flowy_editor/infra/flowy_svg.dart'; -import 'package:flowy_editor/render/rich_text/rich_text_style.dart'; import 'package:flowy_editor/service/default_text_operations/format_rich_text_style.dart'; -import 'package:flutter/material.dart'; typedef ToolbarEventHandler = void Function(EditorState editorState); @@ -13,17 +14,20 @@ ToolbarEventHandlers defaultToolbarEventHandlers = { 'italic': (editorState) => formatItalic(editorState), 'strikethrough': (editorState) => formatStrikethrough(editorState), 'underline': (editorState) => formatUnderline(editorState), - 'quote': ((editorState) {}), - 'number_list': ((editorState) {}), - 'bulleted_list': ((editorState) {}), + 'quote': (editorState) => formatQuote(editorState), + 'number_list': (editorState) {}, + 'bulleted_list': (editorState) => formatBulletedList(editorState), + 'H1': (editorState) => formatHeading(editorState, StyleKey.h1), + 'H2': (editorState) => formatHeading(editorState, StyleKey.h2), + 'H3': (editorState) => formatHeading(editorState, StyleKey.h3), }; List defaultListToolbarEventNames = [ 'H1', 'H2', 'H3', - 'B-List', - 'N-List', + // 'B-List', + // 'N-List', ]; class ToolbarWidget extends StatefulWidget { diff --git a/frontend/app_flowy/packages/flowy_editor/lib/service/default_text_operations/format_rich_text_style.dart b/frontend/app_flowy/packages/flowy_editor/lib/service/default_text_operations/format_rich_text_style.dart index 514a9d706b..73945e5d88 100644 --- a/frontend/app_flowy/packages/flowy_editor/lib/service/default_text_operations/format_rich_text_style.dart +++ b/frontend/app_flowy/packages/flowy_editor/lib/service/default_text_operations/format_rich_text_style.dart @@ -1,27 +1,77 @@ import 'package:flowy_editor/document/attributes.dart'; import 'package:flowy_editor/document/node.dart'; import 'package:flowy_editor/editor_state.dart'; +import 'package:flowy_editor/extensions/text_node_extensions.dart'; import 'package:flowy_editor/operation/transaction_builder.dart'; import 'package:flowy_editor/render/rich_text/rich_text_style.dart'; -import 'package:flowy_editor/extensions/text_node_extensions.dart'; + +void formatHeading(EditorState editorState, String heading) { + formatTextNodes(editorState, { + StyleKey.subtype: StyleKey.heading, + StyleKey.heading: heading, + }); +} + +void formatQuote(EditorState editorState) { + formatTextNodes(editorState, { + StyleKey.subtype: StyleKey.quote, + }); +} + +void formatCheckbox(EditorState editorState) { + formatTextNodes(editorState, { + StyleKey.subtype: StyleKey.checkbox, + StyleKey.checkbox: false, + }); +} + +void formatBulletedList(EditorState editorState) { + formatTextNodes(editorState, { + StyleKey.subtype: StyleKey.bulletedList, + }); +} + +bool formatTextNodes(EditorState editorState, Attributes attributes) { + final nodes = editorState.service.selectionService.currentSelectedNodes.value; + final textNodes = nodes.whereType().toList(); + + if (textNodes.isEmpty) { + return false; + } + + final builder = TransactionBuilder(editorState); + + for (final textNode in textNodes) { + builder.updateNode( + textNode, + Attributes.fromIterable( + StyleKey.globalStyleKeys, + value: (_) => null, + )..addAll(attributes), + ); + } + + builder.commit(); + return true; +} bool formatBold(EditorState editorState) { - return formatRichText(editorState, StyleKey.bold); + return formatRichTextPartialStyle(editorState, StyleKey.bold); } bool formatItalic(EditorState editorState) { - return formatRichText(editorState, StyleKey.italic); + return formatRichTextPartialStyle(editorState, StyleKey.italic); } bool formatUnderline(EditorState editorState) { - return formatRichText(editorState, StyleKey.underline); + return formatRichTextPartialStyle(editorState, StyleKey.underline); } bool formatStrikethrough(EditorState editorState) { - return formatRichText(editorState, StyleKey.strikethrough); + return formatRichTextPartialStyle(editorState, StyleKey.strikethrough); } -bool formatRichText(EditorState editorState, String styleKey) { +bool formatRichTextPartialStyle(EditorState editorState, String styleKey) { final selection = editorState.service.selectionService.currentSelection; final nodes = editorState.service.selectionService.currentSelectedNodes.value; final textNodes = nodes.whereType().toList(growable: false);