Skip to content

Commit

Permalink
Merge branch 'main' into feat-zhiya
Browse files Browse the repository at this point in the history
* main:
  feat: simplify auto scroll behavior in ScrollServiceWidget (AppFlowy-IO#437)
  chore: bump version 1.3.0 (AppFlowy-IO#435)
  fix: better column resize performance (AppFlowy-IO#434)
  fix: table padding and selection (AppFlowy-IO#432)
  fix: table block bugs (AppFlowy-IO#431)
  fix: refactor text alignment handling in block components
  Revert "fix: remove flutter overlay (AppFlowy-IO#358)" (AppFlowy-IO#427)
  feat: support alignment for block component (AppFlowy-IO#425)
  fix: remove flutter overlay (AppFlowy-IO#358)
  feat: toggle highlight using ctrl/cmd + shift + h (AppFlowy-IO#333)
  feat: table plugin (AppFlowy-IO#62)
  feat: editor state update node (AppFlowy-IO#405)
  fix: exception on prev node text direction null (AppFlowy-IO#404)
  fix: html encoder not adding multiple text decorations (AppFlowy-IO#424)
  feat: default text direction property (AppFlowy-IO#402)
  fix: fixed the cursor not moving to next line after inserting divider (AppFlowy-IO#371)
  chore: update theme colors for editor
  feat: refactor floating toolbar positioning logic
  fix: update resizable image width calculation with minimum width constraint
  • Loading branch information
q200892907 committed Sep 5, 2023
2 parents 4e2b29f + 3f2db9b commit 2709672
Show file tree
Hide file tree
Showing 82 changed files with 5,069 additions and 432 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
## 1.3.0
* feat: support table plugin by @zoli in ([#62](https://github.com/AppFlowy-IO/appflowy-editor/pull/62))
* feat: support alignment for block component by @LucasXu0 in ([#425](https://github.com/AppFlowy-IO/appflowy-editor/pull/425))
* feat: toggle highlight using ctrl/cmd + shift + h by @MayurSMahajan in ([#333](https://github.com/AppFlowy-IO/appflowy-editor/pull/333))
* feat: refactor floating toolbar positioning logic by @LucasXu0 in ([#422](https://github.com/AppFlowy-IO/appflowy-editor/pull/42))
* feat: default text direction property by @zoli in ([#402](https://github.com/AppFlowy-IO/appflowy-editor/pull/402))
* fix: rect of the divider block is incorrect by @LucasXu0 in ([#415](https://github.com/AppFlowy-IO/appflowy-editor/pull/415))
* fix: replace matches on the same node by @MayurSMahajan in ([#418](https://github.com/AppFlowy-IO/appflowy-editor/pull/418))
* fix: update resizable image width calculation with minimum width constraint by @LucasXu0 in ([#421](https://github.com/AppFlowy-IO/appflowy-editor/pull/421))
* fix: fixed the cursor not moving to next line after inserting divider by @Mukund-Tandon in ([#371](https://github.com/AppFlowy-IO/appflowy-editor/pull/371))
* fix: html encoder not adding multiple text decorations by @alihassan143 in ([#424](https://github.com/AppFlowy-IO/appflowy-editor/pull/424))
* fix: exception on prev node text direction null by @zoli in ([#404](https://github.com/AppFlowy-IO/appflowy-editor/pull/404))

## 1.2.4
* feat: improve CJK IME support by @LucasXu0 in ([#412](https://github.com/AppFlowy-IO/appflowy-editor/pull/412))
* feat: implement find dialog by @MayurSMahajan in ([#106](https://github.com/AppFlowy-IO/appflowy-editor/pull/106))
Expand Down
6 changes: 3 additions & 3 deletions example/lib/pages/customize_theme_for_editor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class _CustomizeThemeForEditorState extends State<CustomizeThemeForEditor> {

Widget buildEditor(EditorState editorState) {
return Container(
color: Colors.black,
color: Colors.grey[900],
child: AppFlowyEditor(
editorState: editorState,
editorStyle: customizeEditorStyle(),
Expand Down Expand Up @@ -134,11 +134,11 @@ class _CustomizeThemeForEditorState extends State<CustomizeThemeForEditor> {
? const EdgeInsets.only(left: 100, right: 100, top: 20)
: const EdgeInsets.symmetric(horizontal: 20),
cursorColor: Colors.green,
selectionColor: Colors.green,
selectionColor: Colors.green.withOpacity(0.5),
textStyleConfiguration: TextStyleConfiguration(
text: const TextStyle(
fontSize: 18.0,
color: Colors.white54,
color: Colors.white,
),
bold: const TextStyle(
fontWeight: FontWeight.w900,
Expand Down
21 changes: 18 additions & 3 deletions example/lib/pages/editor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ class Editor extends StatelessWidget {
editorState.logConfiguration
..handler = debugPrint
..level = LogLevel.off;
onEditorStateChange(editorState);
editorState.transactionStream.listen((event) {
if (event.$1 == TransactionTime.after) {
onEditorStateChange(editorState);
}
});
final scrollController = ScrollController();
if (PlatformExtension.isDesktopOrWeb) {
return FloatingToolbar(
Expand All @@ -46,7 +50,8 @@ class Editor extends StatelessWidget {
linkItem,
buildTextColorItem(),
buildHighlightColorItem(),
...textDirectionItems
...textDirectionItems,
...alignmentItems,
],
editorState: editorState,
scrollController: scrollController,
Expand Down Expand Up @@ -125,7 +130,17 @@ class Editor extends StatelessWidget {
scrollController: scrollController,
blockComponentBuilders: customBlockComponentBuilders,
commandShortcutEvents: [
...standardCommandShortcutEvents,
customToggleHighlightCommand(
style: ToggleColorsStyle(
highlightColor: Theme.of(context).highlightColor,
),
),
...[
...standardCommandShortcutEvents
..removeWhere(
(el) => el == toggleHighlightCommand,
),
],
...findAndReplaceCommands(
context: context,
localizations: FindReplaceLocalizations(
Expand Down
20 changes: 20 additions & 0 deletions lib/src/editor/block_component/base_component/align_mixin.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/material.dart';

mixin BlockComponentAlignMixin {
Node get node;

Alignment? get alignment {
final alignString = node.attributes[blockComponentAlign] as String?;
switch (alignString) {
case 'center':
return Alignment.center;
case 'right':
return Alignment.centerRight;
case 'left':
return Alignment.centerLeft;
default:
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,20 @@ final _regex = RegExp(
);

mixin BlockComponentTextDirectionMixin {
EditorState get editorState;
Node get node;

TextDirection? lastDirection;

/// Calculate the text direction of a block component.
// defaultTextDirection will be ltr if caller hasn't passed any value.
TextDirection calculateTextDirection({
TextDirection? defaultTextDirection,
}) {
defaultTextDirection ??= TextDirection.ltr;
TextDirection calculateTextDirection({TextDirection? layoutDirection}) {
layoutDirection ??= TextDirection.ltr;

final direction = calculateNodeDirection(
node: node,
defaultTextDirection: defaultTextDirection,
layoutDirection: layoutDirection,
defaultTextDirection: editorState.editorStyle.defaultTextDirection,
lastDirection: lastDirection,
);

Expand All @@ -47,53 +47,61 @@ mixin BlockComponentTextDirectionMixin {
}

/// Calculate the text direction of a node.
// If the textDirection attribute is not set we will use defaultTextDirection.
// If the textDirection attribute is not set, we will use defaultTextDirection if
// it has a value (defaultTextDirection != null). If not will use layoutDirection.
// If the textDirection is ltr or rtl we will apply that.
// If the textDirection is auto we go by these priorities:
// 1. Determine the direction by first character with strong directionality
// 2. lastDirection which is the node last determined direction
// 3. previous line direction
// 4. defaultTextDirection
// 5. layoutDirection
// We will move from first priority when for example the node text is empty or
// it only has characters without strong directionality e.g. '@'.
TextDirection calculateNodeDirection({
required Node node,
required TextDirection defaultTextDirection,
required TextDirection layoutDirection,
String? defaultTextDirection,
TextDirection? lastDirection,
}) {
defaultTextDirection = lastDirection ?? defaultTextDirection;

// if the block component has a text direction attribute which is not auto,
// use it
final value = node.attributes[blockComponentTextDirection] as String?;
final value = (node.attributes[blockComponentTextDirection] as String?) ??
defaultTextDirection;
if (value != null && value != blockComponentTextDirectionAuto) {
return value.toTextDirection(fallback: defaultTextDirection);
final direction = value.toTextDirection();
if (direction != null) {
return direction;
}
}

// previous line direction
final previousNodeContainsTextDirection = node.previousNodeWhere(
(element) => element.attributes.containsKey(blockComponentTextDirection),
);
if (lastDirection == null &&
value == blockComponentTextDirectionAuto &&
previousNodeContainsTextDirection != null) {
final String previousValue = previousNodeContainsTextDirection
.attributes[blockComponentTextDirection];
if (previousValue == blockComponentTextDirectionAuto) {
defaultTextDirection =
previousNodeContainsTextDirection.selectable?.textDirection() ??
defaultTextDirection;
} else {
defaultTextDirection =
previousValue.toTextDirection(fallback: defaultTextDirection);
if (value == blockComponentTextDirectionAuto) {
// previous line direction
final previousNodeContainsTextDirection =
previousOrParentNodeWithTextDirection(node);

if (lastDirection != null) {
defaultTextDirection = lastDirection.name;
} else if (previousNodeContainsTextDirection != null) {
final String previousValue = previousNodeContainsTextDirection
.attributes[blockComponentTextDirection];
if (previousValue == blockComponentTextDirectionAuto) {
defaultTextDirection = previousNodeContainsTextDirection.selectable
?.textDirection()
.name ??
defaultTextDirection;
} else {
defaultTextDirection =
previousValue.toTextDirection()?.name ?? defaultTextDirection;
}
}
}

// if the value is null or the text is null or empty,
// use the default text direction
final text = node.delta?.toPlainText();
if (value == null || text == null || text.isEmpty) {
return defaultTextDirection;
return defaultTextDirection?.toTextDirection() ?? layoutDirection;
}

// if the value is auto and the text isn't null or empty,
Expand All @@ -107,16 +115,31 @@ TextDirection calculateNodeDirection({
}
}

return defaultTextDirection;
return defaultTextDirection?.toTextDirection() ?? layoutDirection;
}

Node? previousOrParentNodeWithTextDirection(Node node) {
bool textDirectionCheck(node) =>
node != null &&
node.attributes.containsKey(blockComponentTextDirection) &&
node.attributes[blockComponentTextDirection] != null;

if (textDirectionCheck(node.previous)) {
return node.previous;
} else if (textDirectionCheck(node.parent)) {
return node.parent;
}

return null;
}

extension on String {
TextDirection toTextDirection({required TextDirection fallback}) {
TextDirection? toTextDirection() {
if (this == blockComponentTextDirectionLTR) {
return TextDirection.ltr;
} else if (this == blockComponentTextDirectionRTL) {
return TextDirection.rtl;
}
return fallback;
return null;
}
}
6 changes: 6 additions & 0 deletions lib/src/editor/block_component/base_component_keys.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,9 @@ const blockComponentTextDirection = 'textDirection';
const blockComponentTextDirectionAuto = 'auto';
const blockComponentTextDirectionLTR = 'ltr';
const blockComponentTextDirectionRTL = 'rtl';

/// text align
///
/// its value must be one of the following:
/// - left, right, center.
const blockComponentAlign = 'align';
79 changes: 37 additions & 42 deletions lib/src/editor/block_component/block_component.dart
Original file line number Diff line number Diff line change
@@ -1,55 +1,50 @@
// paragraph
export 'text_block_component/text_block_component.dart';

// to-do list
export 'todo_list_block_component/todo_list_block_component.dart';
export 'todo_list_block_component/todo_list_character_shortcut.dart';
export 'todo_list_block_component/todo_list_command_shortcut.dart';

export 'base_component/align_mixin.dart';
export 'base_component/background_color_mixin.dart';
export 'base_component/block_component_action_wrapper.dart';
export 'base_component/block_component_configuration.dart';
// base
export 'base_component/convert_to_paragraph_command.dart';
export 'base_component/indent_command.dart';
export 'base_component/insert_newline_in_type_command.dart';
export 'base_component/markdown_format_helper.dart';
export 'base_component/outdent_command.dart';
export 'base_component/text_direction_mixin.dart';
export 'base_component/text_style_configuration.dart';
export 'base_component/widget/full_screen_overlay_entry.dart';
export 'base_component/widget/nested_list_widget.dart';
export 'base_component_keys.dart';
// bulleted list
export 'bulleted_list_block_component/bulleted_list_block_component.dart';
export 'bulleted_list_block_component/bulleted_list_character_shortcut.dart';

// numbered list
export 'numbered_list_block_component/numbered_list_block_component.dart';
export 'numbered_list_block_component/numbered_list_character_shortcut.dart';

// quote
export 'quote_block_component/quote_block_component.dart';
export 'quote_block_component/quote_character_shortcut.dart';

// divider
export 'divider_block_component/divider_block_component.dart';
export 'divider_block_component/divider_character_shortcut.dart';
export 'divider_block_component/divider_menu_item.dart';
// heading
export 'heading_block_component/heading_block_component.dart';
export 'heading_block_component/heading_character_shortcut.dart';

// image
export 'image_block_component/image_block_component.dart';
export 'image_block_component/image_upload_widget.dart';

// divider
export 'divider_block_component/divider_block_component.dart';
export 'divider_block_component/divider_character_shortcut.dart';
export 'divider_block_component/divider_menu_item.dart';

// base
export 'base_component/convert_to_paragraph_command.dart';
export 'base_component/insert_newline_in_type_command.dart';
export 'base_component/indent_command.dart';
export 'base_component/outdent_command.dart';
export 'base_component/widget/full_screen_overlay_entry.dart';

// rich text
export 'rich_text/default_selectable_mixin.dart';
// numbered list
export 'numbered_list_block_component/numbered_list_block_component.dart';
export 'numbered_list_block_component/numbered_list_character_shortcut.dart';
// quote
export 'quote_block_component/quote_block_component.dart';
export 'quote_block_component/quote_character_shortcut.dart';
export 'rich_text/appflowy_rich_text.dart';
export 'rich_text/appflowy_rich_text_keys.dart';

export 'base_component/block_component_configuration.dart';
export 'base_component/text_style_configuration.dart';
export 'base_component/background_color_mixin.dart';
export 'base_component/text_direction_mixin.dart';
export 'base_component/markdown_format_helper.dart';
export 'base_component/widget/nested_list_widget.dart';
export 'base_component/block_component_action_wrapper.dart';

// rich text
export 'rich_text/default_selectable_mixin.dart';
export 'standard_block_components.dart';
export 'base_component_keys.dart';
export 'table_block_component/table_action.dart';
// table
export 'table_block_component/table_block_component.dart';
export 'table_block_component/table_cell_block_component.dart';
export 'table_block_component/table_commands.dart';
export 'text_block_component/text_block_component.dart';
// to-do list
export 'todo_list_block_component/todo_list_block_component.dart';
export 'todo_list_block_component/todo_list_character_shortcut.dart';
export 'todo_list_block_component/todo_list_command_shortcut.dart';
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ class _BulletedListBlockComponentWidgetState
BlockComponentConfigurable,
BlockComponentBackgroundColorMixin,
NestedBlockComponentStatefulWidgetMixin,
BlockComponentTextDirectionMixin {
BlockComponentTextDirectionMixin,
BlockComponentAlignMixin {
@override
final forwardKey = GlobalKey(debugLabel: 'flowy_rich_text');

Expand All @@ -111,12 +112,13 @@ class _BulletedListBlockComponentWidgetState
@override
Widget buildComponent(BuildContext context) {
final textDirection = calculateTextDirection(
defaultTextDirection: Directionality.maybeOf(context),
layoutDirection: Directionality.maybeOf(context),
);

Widget child = Container(
color: backgroundColor,
width: double.infinity,
alignment: alignment,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
Expand All @@ -134,6 +136,7 @@ class _BulletedListBlockComponentWidgetState
key: forwardKey,
node: widget.node,
editorState: editorState,
textAlign: alignment?.toTextAlign,
placeholderText: placeholderText,
textSpanDecorator: (textSpan) => textSpan.updateTextStyle(
textStyle,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ Future<bool> _convertSyntaxToDivider(
..insertNode(path, dividerNode())
..insertNode(path, paragraphNode())
..deleteNode(node)
..afterSelection = Selection.collapsed(Position(path: path));
..afterSelection = Selection.collapsed(Position(path: path.next));
editorState.apply(transaction);
return true;
}
Loading

0 comments on commit 2709672

Please sign in to comment.