appflowy-editor/documentation/customizing.md

269 lines
7.3 KiB
Markdown
Raw Permalink Normal View History

# Customizing Editor Features
## Customizing a Shortcut Event
2022-08-17 21:25:24 +08:00
We will use a simple example to illustrate how to quickly add a shortcut event.
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:
```dart
2023-07-04 14:07:23 +08:00
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 [],
);
}
}
```
2022-08-17 21:25:24 +08:00
At this point, nothing magic will happen after typing `_xxx_`.
![Before](./images/customize_a_shortcut_event_before.gif)
2023-07-04 14:07:23 +08:00
To implement our shortcut event we will create a `CharacterShortcutEvent` instance to handle an underscore input.
2022-09-06 13:14:03 +08:00
2023-07-04 14:07:23 +08:00
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'.
2022-09-06 13:14:03 +08:00
```dart
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/material.dart';
2023-07-04 14:07:23 +08:00
// ...
CharacterShortcutEvent underscoreToItalicEvent = CharacterShortcutEvent(
2022-09-06 13:14:03 +08:00
key: 'Underscore to italic',
2023-07-04 14:07:23 +08:00
character: '_',
handler: (editorState) async => handleFormatByWrappingWithSingleCharacter(
editorState: editorState,
character: '_',
formatStyle: FormatStyleByWrappingWithSingleChar.italic,
),
2022-09-06 13:14:03 +08:00
);
```
2023-07-04 14:07:23 +08:00
Now our 'underscore handler' function is done and the only task left is to inject it into the AppFlowyEditor.
```dart
2023-07-04 14:07:23 +08:00
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/material.dart';
2023-07-04 14:07:23 +08:00
class UnderScoreToItalic extends StatelessWidget {
const UnderScoreToItalic({super.key});
@override
Widget build(BuildContext context) {
return AppFlowyEditor.custom(
editorState: EditorState.blank(withInitialText: true),
blockComponentBuilders: standardBlockComponentBuilderMap,
characterShortcutEvents: [
underScoreToItalicEvent,
],
);
2023-07-04 14:07:23 +08:00
}
}
2023-07-04 14:07:23 +08:00
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)
2023-07-04 14:07:23 +08:00
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.
2023-07-07 16:07:47 +08:00
## Customizing a Theme
2023-07-04 14:07:23 +08:00
2023-07-07 16:07:47 +08:00
We will use a simple example to illustrate how to quickly customize a theme.
Let's start with a blank document:
```dart
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
alignment: Alignment.topCenter,
child: AppFlowyEditor(
2023-07-07 16:07:47 +08:00
editorState: EditorState.blank(),
),
),
);
}
```
2023-07-07 16:07:47 +08:00
At this point, the editor looks like ...
![Before](./images/customizing_a_theme_before.png)
2022-09-16 14:06:46 +08:00
2023-07-07 16:07:47 +08:00
Next, we will customize the `EditorStyle` and the block style with `BlockComponentConfiguration`.
2022-09-16 14:06:46 +08:00
```dart
2023-07-07 16:07:47 +08:00
EditorStyle customizeEditorStyle() {
return EditorStyle(
padding: PlatformExtension.isDesktopOrWeb
? const EdgeInsets.only(left: 100, right: 100, top: 20)
: const EdgeInsets.symmetric(horizontal: 20),
cursorColor: Colors.green,
selectionColor: Colors.green,
textStyleConfiguration: TextStyleConfiguration(
text: const TextStyle(
fontSize: 18.0,
color: Colors.white54,
),
bold: const TextStyle(
fontWeight: FontWeight.w900,
),
href: TextStyle(
color: Colors.amber,
decoration: TextDecoration.combine(
[
TextDecoration.overline,
TextDecoration.underline,
],
),
),
code: const TextStyle(
fontSize: 14.0,
fontStyle: FontStyle.italic,
color: Colors.blue,
backgroundColor: Colors.black12,
2022-09-16 14:06:46 +08:00
),
),
2023-07-07 16:07:47 +08:00
textSpanDecorator: (context, node, index, text, textSpan) {
final attributes = text.attributes;
final href = attributes?[AppFlowyRichTextKeys.href];
if (href != null) {
return TextSpan(
text: text.text,
style: textSpan.style,
recognizer: TapGestureRecognizer()
..onTap = () {
debugPrint('onTap: $href');
},
);
}
return textSpan;
},
2022-09-16 14:06:46 +08:00
);
}
2023-07-07 16:07:47 +08:00
Map<String, BlockComponentBuilder> customBuilder() {
final configuration = BlockComponentConfiguration(
padding: (node) {
if (HeadingBlockKeys.type == node.type) {
return const EdgeInsets.symmetric(vertical: 30);
}
return const EdgeInsets.symmetric(vertical: 10);
},
textStyle: (node) {
if (HeadingBlockKeys.type == node.type) {
return const TextStyle(color: Colors.yellow);
}
return const TextStyle();
},
);
2022-09-16 14:06:46 +08:00
2023-07-07 16:07:47 +08:00
// customize heading block style
return {
...standardBlockComponentBuilderMap,
// heading block
HeadingBlockKeys.type: HeadingBlockComponentBuilder(
configuration: configuration,
),
2023-07-07 16:07:47 +08:00
// todo-list block
TodoListBlockKeys.type: TodoListBlockComponentBuilder(
configuration: configuration,
iconBuilder: (context, node) {
final checked = node.attributes[TodoListBlockKeys.checked] as bool;
return Icon(
checked ? Icons.check_box : Icons.check_box_outline_blank,
size: 20,
color: Colors.white,
);
},
2022-09-16 14:06:46 +08:00
),
2023-07-07 16:07:47 +08:00
// bulleted list block
BulletedListBlockKeys.type: BulletedListBlockComponentBuilder(
configuration: configuration,
iconBuilder: (context, node) {
return const Icon(
Icons.circle,
size: 20,
color: Colors.green,
);
},
),
2023-07-07 16:07:47 +08:00
// quote block
QuoteBlockKeys.type: QuoteBlockComponentBuilder(
configuration: configuration,
iconBuilder: (context, node) {
return const EditorSvg(
width: 20,
height: 20,
padding: EdgeInsets.only(right: 5.0),
name: 'quote',
color: Colors.pink,
);
},
),
2023-07-07 16:07:47 +08:00
};
2022-09-16 14:06:46 +08:00
}
```
Now our 'customize style' 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(
2023-07-07 16:07:47 +08:00
editorState: EditorState.blank(),
editorStyle: customizeEditorStyle(),
blockComponentBuilders: customBuilder(),
2022-09-16 14:06:46 +08:00
),
),
);
}
```
![After](./images/customizing_a_theme_after.png)
## Changing default text direction
The text direction is LTR by default, but you can change it by wrapping AppFlowyEditor with Directionality.
In code snippet below we set the default direction to RTL.
```dart
@override
Widget build(BuildContext context) {
return Scaffold(
body: Directionality(
textDirection: TextDirection.rtl,
child: AppFlowyEditor(
editorState: EditorState.blank(),
),
),
);
}
```