Skip to content

Commit

Permalink
chore: bump version 1.1.0 (#284)
Browse files Browse the repository at this point in the history
  • Loading branch information
LucasXu0 authored Jul 4, 2023
1 parent 2b2bce4 commit bb3771a
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 129 deletions.
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
## 1.1.0
* feat: support IME by @LucasXu0 in ([#253](https://github.com/AppFlowy-IO/appflowy-editor/pull/253))
* feat: support text and background color in mobile toolbar by @hyj1204 in ([#233](https://github.com/AppFlowy-IO/appflowy-editor/pull/233))
* feat: support broadcast the transaction before applying it by @LucasXu0 in ([#226](https://github.com/AppFlowy-IO/appflowy-editor/pull/226))
* feat: support customizing text attribute key and rendering by @LucasXu0 in ([#244](https://github.com/AppFlowy-IO/appflowy-editor/pull/244))
* feat: support customizing the block icon widget by @LucasXu0 in ([#274](https://github.com/AppFlowy-IO/appflowy-editor/pull/274))
* feat: support uploading images from local files by @Mukund-Tandon in ([#232](https://github.com/AppFlowy-IO/appflowy-editor/pull/232))
* feat: add underline syntax parser by @vedant-pandey in ([#256](https://github.com/AppFlowy-IO/appflowy-editor/pull/256))
* feat: migrate the delta encoder by @LucasXu0 in ([#277](https://github.com/AppFlowy-IO/appflowy-editor/pull/277))
* feat: support divider toolbar item in mobile by @hyj1204 in ([#281](https://github.com/AppFlowy-IO/appflowy-editor/pull/281))
* feat: customized color options by @hyj1204 in ([#270](https://github.com/AppFlowy-IO/appflowy-editor/pull/270))
* feat: support exiting link menu by ESC by @vincenzoursano in ([#124](https://github.com/AppFlowy-IO/appflowy-editor/pull/124))
* fix: focus node doesn't work on mobile by @LucasXu0 in ([#227](https://github.com/AppFlowy-IO/appflowy-editor/pull/227))
* fix: the cursor is inaccuracy when the text contains special emoji by @LucasXu0 in ([#238](https://github.com/AppFlowy-IO/appflowy-editor/pull/238))
* fix: extend attribute keys shouldn't be sliced by @LucasXu0 in ([#248](https://github.com/AppFlowy-IO/appflowy-editor/pull/248))
* fix: keep keyboard appearance as same brightness as system theme by @hyj1204 in ([#264](https://github.com/AppFlowy-IO/appflowy-editor/pull/264))

## 1.0.4
* feat: support mobile drag selection by @LucasXu0 in ([#209](https://github.com/AppFlowy-IO/appflowy-editor/pull/209))
* feat: support customizing number of the numbered list by @LucasXu0 in ([#219](https://github.com/AppFlowy-IO/appflowy-editor/pull/219))
Expand Down
42 changes: 21 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,13 @@ and the Flutter guide for
## Key Features

* Build rich, intuitive editors
* Design and modify an ever expanding list of customizable features including
* components (such as form input controls, numbered lists, and rich text widgets)
* Design and modify an ever-expanding list of customizable features including
* block components (such as form input controls, numbered lists, and rich text widgets)
* shortcut events
* themes
* menu options (**coming soon!**)
* [Test-coverage](https://github.com/AppFlowy-IO/appflowy-editor/blob/main/documentation/testing.md) and ongoing maintenance by AppFlowy's core team and community of more than 1,000 builders
* selection menu
* toolbar menu
* [Test Coverage](https://github.com/AppFlowy-IO/appflowy-editor/blob/main/documentation/testing.md) and ongoing maintenance by AppFlowy's core team and community of more than 1,000 builders

## Getting Started

Expand All @@ -54,28 +55,28 @@ flutter pub get
Start by creating a new empty AppFlowyEditor object.

```dart
final editorState = EditorState.empty(); // an empty state
final editor = AppFlowyEditor(
editorState: editorState,
final editorState = EditorState.blank(withInitialText: true); // with an empty paragraph
final editor = AppFlowyEditor.standard(
editorState: editorState,
);
```

You can also create an editor from a JSON object in order to configure your initial state. Or you can [create an editor from Markdown or Quill Delta](https://github.com/AppFlowy-IO/appflowy-editor/blob/main/documentation/importing.md).

```dart
final json = ...;
final editorState = EditorState(Document.fromJson(data));
final editor = AppFlowyEditor(
editorState: editorState,
final json = jsonDecode('YOUR INPUT JSON STRING');
final editorState = EditorState(document: Document.fromJson(json));
final editor = AppFlowyEditor.standard(
editorState: editorState,
);
```

> Note: The parameters `localizationsDelegates` need to be assigned in MaterialApp widget
```dart
MaterialApp(
localizationsDelegates: const [
AppFlowyEditorLocalizations.delegate,
],
localizationsDelegates: const [
AppFlowyEditorLocalizations.delegate,
],
);
```

Expand All @@ -89,25 +90,24 @@ flutter run

## Customizing Your Editor

### Customizing Components
### Customizing Block Components

Please refer to our documentation on customizing AppFlowy for a detailed discussion about [customizing components](https://github.com/AppFlowy-IO/appflowy-editor/blob/main/documentation/customizing.md#customize-a-component).

Below are some examples of component customizations:

* [Checkbox Text](https://github.com/AppFlowy-IO/appflowy-editor/blob/main/lib/src/render/rich_text/checkbox_text.dart) demonstrates how to extend new styles based on existing rich text components
* [Image](https://github.com/AppFlowy-IO/appflowy-editor/blob/main/example/lib/plugin/network_image_node_widget.dart) demonstrates how to extend a new node and render it
* See further examples of [rich-text plugins](https://github.com/AppFlowy-IO/appflowy-editor/blob/main/lib/src/render/rich_text)
* [Todo List Block Component](https://github.com/AppFlowy-IO/appflowy-editor/blob/main/lib/src/editor/block_component/todo_list_block_component/todo_list_block_component.dart) demonstrates how to extend new styles based on existing rich text components
* [Divider Block Component](https://github.com/AppFlowy-IO/appflowy-editor/blob/main/lib/src/editor/block_component/divider_block_component/divider_block_component.dart) demonstrates how to extend a new block component and render it
* See further examples of [Rich-Text Plugins](https://github.com/AppFlowy-IO/appflowy-editor/tree/main/lib/src/editor/block_component)

### Customizing Shortcut Events

Please refer to our documentation on customizing AppFlowy for a detailed discussion about [customizing shortcut events](https://github.com/AppFlowy-IO/appflowy-editor/blob/main/documentation/customizing.md#customize-a-shortcut-event).

Below are some examples of shortcut event customizations:

* [BIUS](https://github.com/AppFlowy-IO/appflowy-editor/blob/main/lib/src/service/internal_key_event_handlers/format_style_handler.dart) demonstrates how to make text bold/italic/underline/strikethrough through shortcut keys
* [Paste HTML](https://github.com/AppFlowy-IO/appflowy-editor/blob/main/lib/src/service/internal_key_event_handlers/copy_paste_handler.dart) gives you an idea on how to handle pasted styles through shortcut keys
* Need more examples? Check out [Internal key event handlers](https://github.com/AppFlowy-IO/appflowy-editor/blob/main/lib/src/service/internal_key_event_handlers)
* [BIUS](https://github.com/AppFlowy-IO/appflowy-editor/tree/main/lib/src/editor/editor_component/service/shortcuts/character_shortcut_events/format_single_character) demonstrates how to make text bold/italic/underline/strikethrough through shortcut keys
* Need more examples? Check out [shortcuts](https://github.com/AppFlowy-IO/appflowy-editor/tree/main/lib/src/editor/editor_component/service/shortcuts)

## Glossary
Please refer to the API documentation.
Expand Down
155 changes: 53 additions & 102 deletions documentation/customizing.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# Customizing Editor Features

Note: `AppFlowyEditor` has since been depreciated and `AppFlowyEditor.standard` or `AppFlowyEditor.custom` should be used instead. To recreate the examples below, you would use `AppFlowyEditor.custom`.

## Customizing a Shortcut Event

We will use a simple example to illustrate how to quickly add a shortcut event.
Expand All @@ -11,137 +9,90 @@ In this example, text that starts and ends with an underscore ( \_ ) character w
Let's start with a blank document:

```dart
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
alignment: Alignment.topCenter,
child: AppFlowyEditor(
editorState: EditorState.empty(),
shortcutEvents: const [],
customBuilders: const {},
),
),
);
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/material.dart';
class UnderScoreToItalic extends StatelessWidget {
const UnderScoreToItalic({super.key});
@override
Widget build(BuildContext context) {
return AppFlowyEditor.custom(
editorState: EditorState.blank(withInitialText: true),
blockComponentBuilders: standardBlockComponentBuilderMap,
characterShortcutEvents: const [],
);
}
}
```

At this point, nothing magic will happen after typing `_xxx_`.

![Before](./images/customize_a_shortcut_event_before.gif)

To implement our shortcut event we will create a `ShortcutEvent` instance to handle an underscore input.
To implement our shortcut event we will create a `CharacterShortcutEvent` instance to handle an underscore input.

We need to define `key` and `command` in a ShortCutEvent object to customize hotkeys. We recommend using the description of your event as a key. For example, if the underscore `_` is defined to make text italic, the key can be 'Underscore to italic'.
We need to define `key` and `character` in a `CharacterShortcutEvent` object to customize hotkeys. We recommend using the description of your event as a key. For example, if the underscore `_` is defined to make text italic, the key can be 'Underscore to italic'.

> The command, made up of a single keyword such as `underscore` or a combination of keywords using the `+` sign in between to concatenate, is a condition that triggers a user-defined function. To see which keywords are available to define a command, please refer to [key_mapping.dart](../lib/src/service/shortcut_event/key_mapping.dart).
> If more than one commands trigger the same handler, then we use ',' to split them. For example, using CTRL and A or CMD and A to 'select all', we describe it as `cmd+a,ctrl+a`(case-insensitive).

```dart
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/material.dart';
ShortcutEvent underscoreToItalicEvent = ShortcutEvent(
// ...
CharacterShortcutEvent underscoreToItalicEvent = CharacterShortcutEvent(
key: 'Underscore to italic',
command: 'shift+underscore',
handler: _underscoreToItalicHandler,
character: '_',
handler: (editorState) async => handleFormatByWrappingWithSingleCharacter(
editorState: editorState,
character: '_',
formatStyle: FormatStyleByWrappingWithSingleChar.italic,
),
);
ShortcutEventHandler _underscoreToItalicHandler = (editorState, event) {
};
```

Then, we need to determine if the currently selected node is a `TextNode` and if the selection is collapsed.

If so, we will continue.
Now our 'underscore handler' function is done and the only task left is to inject it into the AppFlowyEditor.

```dart
// ...
ShortcutEventHandler _underscoreToItalicHandler = (editorState, event) {
// Obtain the selection and selected nodes of the current document through the 'selectionService'
// to determine whether the selection is collapsed and whether the selected node is a text node.
final selectionService = editorState.service.selectionService;
final selection = selectionService.currentSelection.value;
final textNodes = selectionService.currentSelectedNodes.whereType<TextNode>();
if (selection == null || !selection.isSingle || textNodes.length != 1) {
return KeyEventResult.ignored;
}
```

Now, we deal with handling the underscore.

Look for the position of the previous underscore and
1. if one is _not_ found, return without doing anything.
2. if one is found, the text enclosed within the two underscores will be formatted to display in italics.
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/material.dart';
```dart
// ...
ShortcutEventHandler _underscoreToItalicHandler = (editorState, event) {
// ...
final textNode = textNodes.first;
final text = textNode.toRawString();
// Determine if an 'underscore' already exists in the text node and only once.
final firstUnderscore = text.indexOf('_');
final lastUnderscore = text.lastIndexOf('_');
if (firstUnderscore == -1 ||
firstUnderscore != lastUnderscore ||
firstUnderscore == selection.start.offset - 1) {
return KeyEventResult.ignored;
}
class UnderScoreToItalic extends StatelessWidget {
const UnderScoreToItalic({super.key});
// Delete the previous 'underscore',
// update the style of the text surrounded by the two underscores to 'italic',
// and update the cursor position.
final transaction = editorState.transaction
..deleteText(textNode, firstUnderscore, 1)
..formatText(
textNode,
firstUnderscore,
selection.end.offset - firstUnderscore - 1,
{
BuiltInAttributeKey.italic: true,
},
)
..afterSelection = Selection.collapsed(
Position(
path: textNode.path,
offset: selection.end.offset - 1,
),
@override
Widget build(BuildContext context) {
return AppFlowyEditor.custom(
editorState: EditorState.blank(withInitialText: true),
blockComponentBuilders: standardBlockComponentBuilderMap,
characterShortcutEvents: [
underScoreToItalicEvent,
],
);
editorState.apply(transaction);
return KeyEventResult.handled;
};
```

Now our 'underscore handler' function is done and the only task left is to inject it into the AppFlowyEditor.

```dart
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
alignment: Alignment.topCenter,
child: AppFlowyEditor(
editorState: EditorState.empty(),
customBuilders: const {},
shortcutEvents: [
underscoreToItalic,
],
),
),
);
}
}
CharacterShortcutEvent underScoreToItalicEvent = CharacterShortcutEvent(
key: 'Underscore to italic',
character: '_',
handler: (editorState) async => handleFormatByWrappingWithSingleCharacter(
editorState: editorState,
character: '_',
formatStyle: FormatStyleByWrappingWithSingleChar.italic,
),
);
```

![After](./images/customize_a_shortcut_event_after.gif)

Check out the [complete code](https://github.com/AppFlowy-IO/appflowy-editor/blob/main/lib/src/service/internal_key_event_handlers/markdown_syntax_to_styled_text.dart) file of this example.
Check out the [complete code](https://github.com/AppFlowy-IO/appflowy-editor/blob/main/example/lib/samples/underscore_to_italic.dart) file of this example.


## Customizing a Component

> ⚠️ Notes: The content below is outdated.
We will use a simple example to show how to quickly add a custom component.

In this example we will render an image from the network.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ bool handleFormatByWrappingWithSingleCharacter({
// if the text is already formatted, we should remove the format.
final sliced = delta.slice(
headCharIndex + 1,
selection.end.offset - headCharIndex - 1,
selection.end.offset,
);
final result = sliced.everyAttributes((element) => element[style] == true);

Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: appflowy_editor
description: A highly customizable rich-text editor for Flutter. The AppFlowy Editor project for AppFlowy and beyond.
version: 1.0.4
version: 1.1.0
homepage: https://github.com/AppFlowy-IO/appflowy-editor

platforms:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import '../../../../new/infra/testable_editor.dart';
import '../test_helpers/mobile_app_with_toolbar_widget.dart';

void main() {
group('dividerMobileToolbarItem\n', () {
group('dividerMobileToolbarItem', () {
testWidgets(
'If the user tries to insert a divider while some text is selected, no action should be taken',
(WidgetTester tester) async {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,12 @@ void main() async {

expect(result, true);
final after = editorState.getNodeAtPath([0])!;
expect(after.delta!.toPlainText(), '$text1$text2');
expect(after.delta!.toList()[0].attributes, null);
expect(after.delta!.toList()[1].attributes, {'italic': true});
final afterDelta = after.delta!;
expect(afterDelta.toPlainText(), '$text1$text2');
final deltaList = afterDelta.toList();
expect(deltaList.length, 2);
expect(deltaList[0].attributes, null);
expect(deltaList[1].attributes, {'italic': true});
});

// Before
Expand Down

0 comments on commit bb3771a

Please sign in to comment.