Skip to content

Commit

Permalink
doc: Editorial updates to the ReadMe for AppFlowyEditor (AppFlowy-IO#900
Browse files Browse the repository at this point in the history
)

docs: Editorial updates to the ReadMe for AppFlowyEditor
  • Loading branch information
egp415 authored Sep 2, 2022
1 parent 1b9f096 commit 9a01f90
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 82 deletions.
61 changes: 37 additions & 24 deletions frontend/app_flowy/packages/appflowy_editor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,27 @@ and the Flutter guide for

## Key Features

* Allow you to build rich, intuitive editors
* Design and modify it your way by customizing components, shortcut events, and many more coming soon including menu options and themes
* [Test-covered](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/documentation/testing.md) and maintained by AppFlowy's core team along with a community of more than 1,000 builders
* 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)
* shortcut events
* menu options (**coming soon!**)
* themes (**coming soon!**)
* [Test-coverage](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/documentation/testing.md) and on-going maintenance by AppFlowy's core team and community of more than 1,000 builders

## Getting Started

## Getting started
Add the AppFlowy editor [Flutter package](https://docs.flutter.dev/development/packages-and-plugins/using-packages) to your environment.

```shell
flutter pub add appflowy_editor
flutter pub get
```

## How to use
## Creating Your First Editor

Start by creating a new empty AppFlowyEditor object.

Let's create a new AppFlowyEditor object
```dart
final editorState = EditorState.empty(); // an empty state
final editor = AppFlowyEditor(
Expand All @@ -50,7 +56,8 @@ final editor = AppFlowyEditor(
);
```

You can also create an editor from a JSON file
You can also create an editor from a JSON object in order to configure your initial state.

```dart
final json = ...;
final editorState = EditorState(StateTree.fromJson(data));
Expand All @@ -61,37 +68,43 @@ final editor = AppFlowyEditor(
);
```

To get a sense for how you might use it, run this example:
To get a sense for how the AppFlowy Editor works, run our example:

```shell
git clone https://github.com/AppFlowy-IO/AppFlowy.git
cd frontend/app_flowy/packages/appflowy_editor/example
flutter run
```

## Customizing Your Editor

### Customizing Components

## How to customize
### Customize a component
Please refer to [customizing a component](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/documentation/customizing.md#customize-a-component) for more details.
Please refer to our documentation on customizing AppFlowy for a detailed discussion about [customizing components](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/documentation/customizing.md#customize-a-component).

Below are some examples of component customizations:

### Customize a shortcut event
Please refer to [customizing a shortcut event](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/documentation/customizing.md#customize-a-shortcut-event) for more details.
* [Checkbox Text](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/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/blob/main/frontend/app_flowy/packages/appflowy_editor/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/blob/main/frontend/app_flowy/packages/appflowy_editor/lib/src/render/rich_text)

### Customizing Shortcut Events

## More Examples
* Customize a component
* [Checkbox Text](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/lib/src/render/rich_text/checkbox_text.dart) shows you how to extend new styles based on existing rich text components
* [Image](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/example/lib/plugin/network_image_node_widget.dart) teaches you how to extend a new node and render it
* And more examples on [rich-text plugins](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/lib/src/render/rich_text)
* Customize a shortcut event
* [BIUS](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/update_text_style_by_command_x_handler.dart) shows you how to make text bold/italic/underline/strikethrough through shortcut keys
* [Paste HTML](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/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/blob/main/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers)
Please refer to our documentation on customizing AppFlowy for a detailed discussion about [customizing shortcut events](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/documentation/customizing.md#customize-a-shortcut-event).

Below are some examples of shortcut event customizations:

* [BIUS](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/update_text_style_by_command_x_handler.dart) demonstrates how to make text bold/italic/underline/strikethrough through shortcut keys
* [Paste HTML](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/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/blob/main/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers)

## Glossary
Please refer to the API documentation.

## Contributing
Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are greatly appreciated. Please look at [CONTRIBUTING.md](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/contributing-to-appflowy) for details.
Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are greatly appreciated.

Please look at [CONTRIBUTING.md](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/contributing-to-appflowy) for details.

## License
Distributed under the AGPLv3 License. See LICENSE for more information.
Distributed under the AGPLv3 License. See [LICENSE](https://github.com/AppFlowy-IO/AppFlowy-Docs/blob/main/LICENSE) for more information.
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# How to customize ...
# Customizing Editor Features

## Customize a shortcut event
## Customizing a Shortcut Event

We will use a simple example to illustrate how to quickly add a shortcut event.

For example, typing `_xxx_` will be converted into _xxx_.
In this example, text that starts and ends with an underscore ( \_ ) character will be rendered in italics for emphasis. So typing `_xxx_` will automatically be converted into _xxx_.

Let's start with a blank document.
Let's start with a blank document:

```dart
@override
Expand All @@ -27,31 +27,33 @@ At this point, nothing magic will happen after typing `_xxx_`.

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

Next, we will create a function to handle an underscore input.
To implement our shortcut event we will create a function to handle an underscore input.

```dart
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
FlowyKeyEventHandler underscoreToItalicHandler = (editorState, event) {
// Since we only need to handler the input of `underscore`.
// All inputs except `underscore` will be ignored directly.
// Since we only need to handle the input of an 'underscore' character,
// all inputs except `underscore` will be ignored immediately.
if (event.logicalKey != LogicalKeyboardKey.underscore) {
return KeyEventResult.ignored;
}
};
```

Then, we need to determine if the currently selected node is `TextNode` and the selection is collapsed.
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
// ...
FlowyKeyEventHandler underscoreToItalicHandler = (editorState, event) {
// ...
// Obtaining the selection and selected nodes of the current document through `selectionService`.
// And determine whether the selection is collapsed and whether the selected node is a text node.
// 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>();
Expand All @@ -60,11 +62,11 @@ FlowyKeyEventHandler underscoreToItalicHandler = (editorState, event) {
}
```

Now, we start dealing with underscore.
Now, we deal with handling the underscore.

Look for the position of the previous underscore and
1. return, if not found.
2. if found, the text wrapped in between two underscores will be displayed in italic.
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
// ...
Expand All @@ -73,14 +75,14 @@ FlowyKeyEventHandler underscoreToItalicHandler = (editorState, event) {
final textNode = textNodes.first;
final text = textNode.toRawString();
// Determine if `underscore` already exists in the text node
// Determine if an 'underscore' already exists in the text node
final previousUnderscore = text.indexOf('_');
if (previousUnderscore == -1) {
return KeyEventResult.ignored;
}
// Delete the previous `underscore`,
// update the style of the text surrounded by two underscores to `italic`,
// Delete the previous 'underscore',
// update the style of the text surrounded by the two underscores to 'italic',
// and update the cursor position.
TransactionBuilder(editorState)
..deleteText(textNode, previousUnderscore, 1)
Expand All @@ -99,7 +101,7 @@ FlowyKeyEventHandler underscoreToItalicHandler = (editorState, event) {
};
```

So far, the '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
@override
Expand All @@ -120,14 +122,15 @@ Widget build(BuildContext context) {

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

[Complete code example]()
Check out the [complete code](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/example/lib/plugin/underscore_to_italic_key_event_handler.dart) file of this example.


## Customize a component
We will use a simple example to showcase how to quickly add a custom component.
## Customizing a Component
We will use a simple example to show how to quickly add a custom component.

For example, we want to render an image from the network.
In this example we will render an image from the network.

To start with, let's create an empty document by running commands as follows:
Let's start with a blank document:

```dart
@override
Expand All @@ -144,9 +147,9 @@ Widget build(BuildContext context) {
}
```

Next, we choose a unique string for your custom node's type. We use `network_image` in this case. And we add `network_image_src` to the `attributes` to describe the link of the image.
Next, we will choose a unique string for your custom node's type.

> For the definition of the [Node](), please refer to this [link]().
We'll use `network_image` in this case. And we add `network_image_src` to the `attributes` to describe the link of the image.

```JSON
{
Expand All @@ -157,9 +160,9 @@ Next, we choose a unique string for your custom node's type. We use `network_ima
}
```

Then, we create a class that inherits [NodeWidgetBuilder](). As shown in the autoprompt, we need to implement two functions:
Then, we create a class that inherits [NodeWidgetBuilder](../lib/src/service/render_plugin_service.dart). As shown in the autoprompt, we need to implement two functions:
1. one returns a widget
2. the other verifies the correctness of the [Node]().
2. the other verifies the correctness of the [Node](../lib/src/document/node.dart).


```dart
Expand All @@ -179,9 +182,7 @@ class NetworkImageNodeWidgetBuilder extends NodeWidgetBuilder {

Now, let's implement a simple image widget based on `Image`.

**It is important to note that the `State` of the returned `Widget` must be with [Selectable]().**

> For the definition of the [Selectable](), please refer to this [link]().
Note that the `State` object that is returned by the `Widget` must implement [Selectable](../lib/src/render/selection/selectable.dart) using the `with` keyword.

```dart
class _NetworkImageNodeWidget extends StatefulWidget {
Expand Down Expand Up @@ -236,7 +237,7 @@ class __NetworkImageNodeWidgetState extends State<_NetworkImageNodeWidget>
}
```

Finally, we return `_NetworkImageNodeWidget` in the `build` function of `NetworkImageNodeWidgetBuilder` and register `NetworkImageNodeWidgetBuilder` into `AppFlowyEditor`.
Finally, we return `_NetworkImageNodeWidget` in the `build` function of `NetworkImageNodeWidgetBuilder`...

```dart
class NetworkImageNodeWidgetBuilder extends NodeWidgetBuilder {
Expand All @@ -256,6 +257,8 @@ class NetworkImageNodeWidgetBuilder extends NodeWidgetBuilder {
}
```

... and register `NetworkImageNodeWidgetBuilder` in the `AppFlowyEditor`.

```dart
final editorState = EditorState(
document: StateTree.empty()
Expand All @@ -281,6 +284,6 @@ return AppFlowyEditor(
);
```

![](./images/customizing_a_component.gif)
![Whew!](./images/customizing_a_component.gif)

[Here you can check out the complete code file of this example]()
Check out the [complete code](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/example/lib/plugin/network_image_node_widget.dart) file of this example.
Loading

0 comments on commit 9a01f90

Please sign in to comment.