mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
docs: extending.md
This commit is contained in:
parent
2224aa271e
commit
2c1b82a916
@ -76,12 +76,16 @@ cd frontend/app_flowy/packages/flowy_editor/example
|
||||
flutter run
|
||||
```
|
||||
|
||||
## How to extends
|
||||
### Extending a custom components
|
||||
Please look at [extending.md](documentation/extending.md) for more details.
|
||||
|
||||
## Examples
|
||||
* Extends custom components.
|
||||
* Extends a custom component.
|
||||
* [Checkbox Text](https://github.com/LucasXu0/AppFlowy/blob/documentation/flowy_editor/frontend/app_flowy/packages/flowy_editor/lib/src/render/rich_text/checkbox_text.dart) - Showing how to extend new styles based on existing rich text components.
|
||||
* [Image](https://github.com/LucasXu0/AppFlowy/blob/documentation/flowy_editor/frontend/app_flowy/packages/flowy_editor/example/lib/plugin/image_node_widget.dart) - Showing how to extend a new node and render it.
|
||||
* More examples. [rich text plugins](https://github.com/LucasXu0/AppFlowy/tree/documentation/flowy_editor/frontend/app_flowy/packages/flowy_editor/lib/src/render/rich_text)
|
||||
* Extends custom shortcut keys.
|
||||
* Extends a custom shortcut key.
|
||||
* [BUIS](https://github.com/LucasXu0/AppFlowy/blob/documentation/flowy_editor/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/update_text_style_by_command_x_handler.dart) - Showing how to make text bold/underline/italic/strikethrough through shortcut keys
|
||||
* [Paste HTML](https://github.com/LucasXu0/AppFlowy/blob/documentation/flowy_editor/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers/copy_paste_handler.dart) - Showing how to handle pasted styles through shortcut keys
|
||||
* More examples. [internal key event handlers](https://github.com/LucasXu0/AppFlowy/tree/documentation/flowy_editor/frontend/app_flowy/packages/flowy_editor/lib/src/service/internal_key_event_handlers)
|
||||
|
@ -0,0 +1,138 @@
|
||||
# How to extends
|
||||
|
||||
## Extending a custom shortcut event
|
||||
we will use a simple example to describe how to quickly extend shortcut event.
|
||||
|
||||
For example, typing `_xxx_` will be converted into _xxx_.
|
||||
|
||||
To start with, we build the simplest example, just a blank document.
|
||||
|
||||
```dart
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Container(
|
||||
alignment: Alignment.topCenter,
|
||||
child: FlowyEditor(
|
||||
editorState: EditorState.empty(),
|
||||
keyEventHandlers: const [],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
Nothing will happen after typing `_xxx_`.
|
||||
|
||||

|
||||
|
||||
Next, we will create a function to handler underscore input.
|
||||
|
||||
```dart
|
||||
import 'package:flowy_editor/flowy_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.
|
||||
if (event.logicalKey != LogicalKeyboardKey.underscore) {
|
||||
return KeyEventResult.ignored;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Then, we need to determine if the currently selected node is `TextNode` and is a single-select case, because for the multi-select case, underscore input should be considered as replacement.
|
||||
|
||||
```dart
|
||||
// ...
|
||||
FlowyKeyEventHandler underscoreToItalicHandler = (editorState, event) {
|
||||
// ...
|
||||
|
||||
// Obtaining the selection and selected nodes of the current document through `selectionService`.
|
||||
// And determine whether it is a single selection 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 start working on underscore logic by looking for the position of the previous underscore and returning if not found. If found, the text wrapped in the two underscores will be converted info italic.
|
||||
|
||||
```dart
|
||||
// ...
|
||||
FlowyKeyEventHandler underscoreToItalicHandler = (editorState, event) {
|
||||
// ...
|
||||
|
||||
final textNode = textNodes.first;
|
||||
final text = textNode.toRawString();
|
||||
// Determine if `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`,
|
||||
// and update the cursor position.
|
||||
TransactionBuilder(editorState)
|
||||
..deleteText(textNode, previousUnderscore, 1)
|
||||
..formatText(
|
||||
textNode,
|
||||
previousUnderscore,
|
||||
selection.end.offset - previousUnderscore - 1,
|
||||
{'italic': true},
|
||||
)
|
||||
..afterSelection = Selection.collapsed(
|
||||
Position(path: textNode.path, offset: selection.end.offset - 1),
|
||||
)
|
||||
..commit();
|
||||
|
||||
return KeyEventResult.handled;
|
||||
};
|
||||
```
|
||||
|
||||
So far, the 'underscore handler' function has completed and only needs to be injected info AppFlowyEditor.
|
||||
|
||||
```dart
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Container(
|
||||
alignment: Alignment.topCenter,
|
||||
child: FlowyEditor(
|
||||
editorState: EditorState.empty(),
|
||||
keyEventHandlers: [
|
||||
underscoreToItalicHandler,
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
|
||||
[Complete code example]()
|
||||
|
||||
## Extending a custom component
|
||||
we will use a simple example to describe how to quickly extend custom component.
|
||||
/// 1. define your custom type in example.json
|
||||
/// For example I need to define an image plugin, then I define type equals
|
||||
/// "image", and add "image_src" into "attributes".
|
||||
/// {
|
||||
/// "type": "image",
|
||||
/// "attributes", { "image_src": "https://s1.ax1x.com/2022/07/28/vCgz1x.png" }
|
||||
/// }
|
||||
/// 2. create a class extends [NodeWidgetBuilder]
|
||||
/// 3. override the function `Widget build(NodeWidgetContext<Node> context)`
|
||||
/// and return a widget to render. The returned widget should be
|
||||
/// a StatefulWidget and mixin with [Selectable].
|
||||
///
|
||||
/// 4. override the getter `nodeValidator`
|
||||
/// to verify the data structure in [Node].
|
||||
/// 5. register the plugin with `type` to `flowy_editor` in `main.dart`.
|
||||
/// 6. Congratulations!
|
||||
1. define your custom `type`.
|
Binary file not shown.
After Width: | Height: | Size: 101 KiB |
Binary file not shown.
After Width: | Height: | Size: 84 KiB |
@ -0,0 +1,46 @@
|
||||
import 'package:flowy_editor/flowy_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.
|
||||
if (event.logicalKey != LogicalKeyboardKey.underscore) {
|
||||
return KeyEventResult.ignored;
|
||||
}
|
||||
|
||||
// Obtaining the selection and selected nodes of the current document through `selectionService`,
|
||||
// and determine whether it is a single selection 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;
|
||||
}
|
||||
|
||||
final textNode = textNodes.first;
|
||||
final text = textNode.toRawString();
|
||||
// Determine if `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`,
|
||||
// and update the cursor position.
|
||||
TransactionBuilder(editorState)
|
||||
..deleteText(textNode, previousUnderscore, 1)
|
||||
..formatText(
|
||||
textNode,
|
||||
previousUnderscore,
|
||||
selection.end.offset - previousUnderscore - 1,
|
||||
{'italic': true},
|
||||
)
|
||||
..afterSelection = Selection.collapsed(
|
||||
Position(path: textNode.path, offset: selection.end.offset - 1),
|
||||
)
|
||||
..commit();
|
||||
|
||||
return KeyEventResult.handled;
|
||||
};
|
Loading…
Reference in New Issue
Block a user