chore: bump version 1.1.0 (#284)

This commit is contained in:
Lucas.Xu 2023-07-04 14:07:23 +08:00 • committed by GitHub
commit bb3771af63
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 100 additions and 129 deletions

View file

@ -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 ## 1.0.4
* feat: support mobile drag selection by @LucasXu0 in ([#209](https://github.com/AppFlowy-IO/appflowy-editor/pull/209)) * 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)) * feat: support customizing number of the numbered list by @LucasXu0 in ([#219](https://github.com/AppFlowy-IO/appflowy-editor/pull/219))

View file

@ -33,12 +33,13 @@ and the Flutter guide for
## Key Features ## Key Features
* Build rich, intuitive editors * Build rich, intuitive editors
* Design and modify an ever expanding list of customizable features including * Design and modify an ever-expanding list of customizable features including
* components (such as form input controls, numbered lists, and rich text widgets) * block components (such as form input controls, numbered lists, and rich text widgets)
* shortcut events * shortcut events
* themes * themes
* menu options (**coming soon!**) * selection 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 * 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 ## Getting Started
@ -54,8 +55,8 @@ flutter pub get
Start by creating a new empty AppFlowyEditor object. Start by creating a new empty AppFlowyEditor object.
```dart ```dart
final editorState = EditorState.empty(); // an empty state final editorState = EditorState.blank(withInitialText: true); // with an empty paragraph
final editor = AppFlowyEditor( final editor = AppFlowyEditor.standard(
editorState: editorState, editorState: editorState,
); );
``` ```
@ -63,9 +64,9 @@ final editor = AppFlowyEditor(
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). 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 ```dart
final json = ...; final json = jsonDecode('YOUR INPUT JSON STRING');
final editorState = EditorState(Document.fromJson(data)); final editorState = EditorState(document: Document.fromJson(json));
final editor = AppFlowyEditor( final editor = AppFlowyEditor.standard(
editorState: editorState, editorState: editorState,
); );
``` ```
@ -89,15 +90,15 @@ flutter run
## Customizing Your Editor ## 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). 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: 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 * [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
* [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 * [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/blob/main/lib/src/render/rich_text) * See further examples of [Rich-Text Plugins](https://github.com/AppFlowy-IO/appflowy-editor/tree/main/lib/src/editor/block_component)
### Customizing Shortcut Events ### Customizing Shortcut Events
@ -105,9 +106,8 @@ Please refer to our documentation on customizing AppFlowy for a detailed discuss
Below are some examples of shortcut event customizations: 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 * [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
* [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 [shortcuts](https://github.com/AppFlowy-IO/appflowy-editor/tree/main/lib/src/editor/editor_component/service/shortcuts)
* 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)
## Glossary ## Glossary
Please refer to the API documentation. Please refer to the API documentation.

View file

@ -1,7 +1,5 @@
# Customizing Editor Features # 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 ## Customizing a Shortcut Event
We will use a simple example to illustrate how to quickly add a shortcut event. We will use a simple example to illustrate how to quickly add a shortcut event.
@ -11,137 +9,90 @@ In this example, text that starts and ends with an underscore ( \_ ) character w
Let's start with a blank document: Let's start with a blank document:
```dart ```dart
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/material.dart';
class UnderScoreToItalic extends StatelessWidget {
const UnderScoreToItalic({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return AppFlowyEditor.custom(
body: Container( editorState: EditorState.blank(withInitialText: true),
alignment: Alignment.topCenter, blockComponentBuilders: standardBlockComponentBuilderMap,
child: AppFlowyEditor( characterShortcutEvents: const [],
editorState: EditorState.empty(),
shortcutEvents: const [],
customBuilders: const {},
),
),
); );
} }
}
``` ```
At this point, nothing magic will happen after typing `_xxx_`. At this point, nothing magic will happen after typing `_xxx_`.
![Before](./images/customize_a_shortcut_event_before.gif) ![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 ```dart
import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
ShortcutEvent underscoreToItalicEvent = ShortcutEvent( // ...
CharacterShortcutEvent underscoreToItalicEvent = CharacterShortcutEvent(
key: 'Underscore to italic', key: 'Underscore to italic',
command: 'shift+underscore', character: '_',
handler: _underscoreToItalicHandler, handler: (editorState) async => handleFormatByWrappingWithSingleCharacter(
); editorState: editorState,
character: '_',
ShortcutEventHandler _underscoreToItalicHandler = (editorState, event) { formatStyle: FormatStyleByWrappingWithSingleChar.italic,
};
```
Then, we need to determine if the currently selected node is a `TextNode` and if the selection is collapsed.
If so, we will continue.
```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.
```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;
}
// 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,
), ),
); );
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. Now our 'underscore handler' function is done and the only task left is to inject it into the AppFlowyEditor.
```dart ```dart
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/material.dart';
class UnderScoreToItalic extends StatelessWidget {
const UnderScoreToItalic({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return AppFlowyEditor.custom(
body: Container( editorState: EditorState.blank(withInitialText: true),
alignment: Alignment.topCenter, blockComponentBuilders: standardBlockComponentBuilderMap,
child: AppFlowyEditor( characterShortcutEvents: [
editorState: EditorState.empty(), underScoreToItalicEvent,
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) ![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 ## Customizing a Component
> ⚠️ Notes: The content below is outdated.
We will use a simple example to show how to quickly add a custom component. 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. In this example we will render an image from the network.

View file

@ -78,7 +78,7 @@ bool handleFormatByWrappingWithSingleCharacter({
// if the text is already formatted, we should remove the format. // if the text is already formatted, we should remove the format.
final sliced = delta.slice( final sliced = delta.slice(
headCharIndex + 1, headCharIndex + 1,
selection.end.offset - headCharIndex - 1, selection.end.offset,
); );
final result = sliced.everyAttributes((element) => element[style] == true); final result = sliced.everyAttributes((element) => element[style] == true);

View file

@ -1,6 +1,6 @@
name: appflowy_editor name: appflowy_editor
description: A highly customizable rich-text editor for Flutter. The AppFlowy Editor project for AppFlowy and beyond. 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 homepage: https://github.com/AppFlowy-IO/appflowy-editor
platforms: platforms:

View file

@ -5,7 +5,7 @@ import '../../../../new/infra/testable_editor.dart';
import '../test_helpers/mobile_app_with_toolbar_widget.dart'; import '../test_helpers/mobile_app_with_toolbar_widget.dart';
void main() { void main() {
group('dividerMobileToolbarItem\n', () { group('dividerMobileToolbarItem', () {
testWidgets( testWidgets(
'If the user tries to insert a divider while some text is selected, no action should be taken', 'If the user tries to insert a divider while some text is selected, no action should be taken',
(WidgetTester tester) async { (WidgetTester tester) async {

View file

@ -150,9 +150,12 @@ void main() async {
expect(result, true); expect(result, true);
final after = editorState.getNodeAtPath([0])!; final after = editorState.getNodeAtPath([0])!;
expect(after.delta!.toPlainText(), '$text1$text2'); final afterDelta = after.delta!;
expect(after.delta!.toList()[0].attributes, null); expect(afterDelta.toPlainText(), '$text1$text2');
expect(after.delta!.toList()[1].attributes, {'italic': true}); final deltaList = afterDelta.toList();
expect(deltaList.length, 2);
expect(deltaList[0].attributes, null);
expect(deltaList[1].attributes, {'italic': true});
}); });
// Before // Before