Browse Source

doc: Editorial updates to the ReadMe for AppFlowyEditor (#900)

docs: Editorial updates to the ReadMe for AppFlowyEditor
Eric Phillips 2 years ago
parent
commit
9a01f90aee

+ 37 - 24
frontend/app_flowy/packages/appflowy_editor/README.md

@@ -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(
@@ -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));
@@ -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.

+ 35 - 32
frontend/app_flowy/packages/appflowy_editor/documentation/customizing.md

@@ -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
@@ -27,7 +27,7 @@ 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';
@@ -35,23 +35,25 @@ 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>();
@@ -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
 // ...
@@ -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)
@@ -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
@@ -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
@@ -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
 {
@@ -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
@@ -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 {
@@ -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 {
@@ -256,6 +257,8 @@ class NetworkImageNodeWidgetBuilder extends NodeWidgetBuilder {
 }
 ```
 
+... and register `NetworkImageNodeWidgetBuilder` in the `AppFlowyEditor`.
+ 
 ```dart
 final editorState = EditorState(
   document: StateTree.empty()
@@ -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.

+ 43 - 26
frontend/app_flowy/packages/appflowy_editor/documentation/testing.md

@@ -1,24 +1,33 @@
 # Testing
 
-> The directory structure of test files is consistent with the code files, making it easy for us to map a file with the corresponding test and check if the test is updated
+The directory structure of test files mirrors that of the code files, making it easy for us to map a file with the corresponding test and check if the test is updated.
 
-## Testing Functions
+For an overview of testing best practices in Flutter applications, please refer to Flutter's [introduction to widget testing](https://docs.flutter.dev/cookbook/testing/widget/introduction) as well as their [introduction to unit testing](https://docs.flutter.dev/cookbook/testing/unit/introduction).
+There you will learn how to do such things as such as simulate a click as well as leverage the `test` and `expect` functions.
+
+## Testing Basic Editor Functions
+
+The example code below shows how to construct a document that will be used in our testing.
 
-**Construct a document for testing**
 ```dart
 const text = 'Welcome to Appflowy 😁';
-// Get the instance of editor.
+// Get the instance of the editor.
 final editor = tester.editor;
-// Insert empty text node.
+
+// Insert an empty text node.
 editor.insertEmptyTextNode();
-// Insert text node with string.
+
+// Insert a text node with the text string we defined earlier.
 editor.insertTextNode(text);
-// Insert text node with heading style.
+
+// Insert the same text, but with the heading style.
 editor.insertTextNode(text, attributes: {
     StyleKey.subtype: StyleKey.heading,
     StyleKey.heading: StyleKey.h1,
 });
-// Insert text node with bulleted list style and bold style.
+
+// Insert our text with the bulleted list style and the bold style.
+// If you want to modify the style of the inserted text, you need to use the Delta parameter.
 editor.insertTextNode(
     '',
     attributes: {
@@ -30,66 +39,76 @@ editor.insertTextNode(
 );
 ```
 
-**The `startTesting` function must be called before testing**.
+The `startTesting` function of the editor must be called before you begin your test.
+
 ```dart
 await editor.startTesting();
 ```
 
-**Get the number of nodes in the document**
+Get the number of nodes in the document.
+
 ```dart
 final length = editor.documentLength;
 print(length);
 ```
 
-**Get the node of a defined path**
+Get the node of a defined path. In this case we are getting the first node of the document which is the text "Welcome to Appflowy 😁".
+
 ```dart
 final firstTextNode = editor.nodeAtPath([0]) as TextNode;
 ```
 
-**Update selection**
+Update the [Selection](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/lib/src/document/selection.dart) so that our text "Welcome to Appflowy 😁" is selected. We will start our selection from the beginning of the string.
+
 ```dart
 await editor.updateSelection(
     Selection.single(path: firstTextNode.path, startOffset: 0),
 );
 ```
 
-**Get the selection**
+Get the current selection.
+
 ```dart
 final selection = editor.documentSelection;
 print(selection);
 ```
 
-**Simulate shortcut event inputs**
+Next we will simulate the input of a shortcut key being pressed that will select all the text.
+
 ```dart
-// Command + A.
+// Meta + A.
 await editor.pressLogicKey(LogicalKeyboardKey.keyA, isMetaPressed: true);
-// Command + shift + S.
+// Meta + shift + S.
 await editor.pressLogicKey(
-    LogicalKeyboardKey.keyS, 
-    isMetaPressed: true, 
+    LogicalKeyboardKey.keyS,
+    isMetaPressed: true,
     isShiftPressed: true,
 );
 ```
 
-**Simulate a text input**
+We will then simulate text input.
+
 ```dart
 // Insert 'Hello World' at the beginning of the first node.
 editor.insertText(firstTextNode, 'Hello World', 0);
 ```
 
-**Get information about the text node**
+Once the text has been added, we can get information about the text node.
+
 ```dart
-// Get plain text.
+// Get the text of the first text node as plain text
 final textAfterInserted = firstTextNode.toRawString();
 print(textAfterInserted);
-// Get attributes.
+// Get the attributes of the text node
 final attributes = firstTextNode.attributes;
 print(attributes);
 ```
 
-## Example
-For example, we are going to test `select_all_handler.dart`
+## A Complete Code Example
 
+In the example code below we are going to test `select_all_handler.dart` by inserting 100 lines of text that read "Welcome to Appflowy 😁" and then simulating the "selectAll" shortcut key being pressed.
+
+Afterwards, we will `expect` that the current selection of the editor is equal to the selection of all the lines that were generated.
 
 ```dart
 import 'package:appflowy_editor/appflowy_editor.dart';
@@ -124,5 +143,3 @@ void main() async {
   });
 }
 ```
-
-For more information about testing, such as simulating a click, please refer to [An introduction to widget testing](https://docs.flutter.dev/cookbook/testing/widget/introduction)