Overview
The Quill Delta plugin enables importing content from editors that use the Quill Delta format. This provides compatibility with Quill-based editors and applications.
This plugin currently supports importing only (Quill Delta → AppFlowy Document). Export from AppFlowy to Quill Delta is not yet supported.
Installation
The Quill Delta encoder is included with AppFlowy Editor:
import 'package:appflowy_editor/appflowy_editor.dart';
What is Quill Delta?
Quill Delta is a JSON-based format used by the Quill editor to represent rich text documents. It consists of an array of operations that describe document content and formatting.
Example Quill Delta:
[
{"insert": "Hello AppFlowy!"},
{"attributes": {"header": 1}, "insert": "\n"}
]
Importing Quill Delta
Basic Usage
Convert Quill Delta JSON to an AppFlowy document:
const json = r'''[{"insert":"Hello AppFlowy!"},{"attributes":{"header":1},"insert":"\n"}]''';
final delta = Delta.fromJson(jsonDecode(json));
final document = quillDeltaEncoder.convert(delta);
final editorState = EditorState(document: document);
Complete Example
From the documentation:
// From documentation/importing.md:38-44
const json = r'''[{"insert":"Hello AppFlowy!"},{"attributes":{"header":1},"insert":"\n"}]''';
final delta = Delta.fromJson(jsonDecode(json));
final document = quillDeltaEncoder.convert(delta);
final editorState = EditorState(document: document);
Supported Quill Attributes
The Quill Delta encoder supports these attributes:
Block-Level Attributes
- Headers:
{"header": 1-6} → Heading levels 1-6
- Lists:
{"list": "bullet"} → Bulleted list
{"list": "ordered"} → Numbered list
{"list": "checked"} → Checked todo list
{"list": "unchecked"} → Unchecked todo list
- Block quote:
{"blockquote": true} → Quote block
- Indentation:
{"indent": 1-9} → Indented content
Text-Level Attributes
- Bold:
{"bold": true}
- Italic:
{"italic": true}
- Underline:
{"underline": true}
- Strikethrough:
{"strike": true}
- Links:
{"link": "url"}
- Text color:
{"color": "#FF0000"} or {"color": "rgba(255,0,0,1)"}
- Background color:
{"background": "#FFFF00"} or {"background": "rgba(255,255,0,1)"}
Implementation Details
Quill Delta Encoder Class
The encoder is implemented in /lib/src/plugins/quill_delta/quill_delta_encoder.dart:18-236:
final QuillDeltaEncoder quillDeltaEncoder = QuillDeltaEncoder();
class QuillDeltaEncoder extends Converter<Delta, Document> {
@override
Document convert(Delta input) {
final iterator = input.iterator;
final document = Document.blank(withInitialText: false);
Node node = paragraphNode();
// ... conversion logic
return document;
}
}
Nested Lists
The encoder handles nested lists using indentation:
// From quill_delta_encoder.dart:40-49
if (_isIndentBulletedList(attributes)) {
final level = _indentLevel(attributes);
final path = [
...nestedLists[level - 1]!.last.path,
nestedLists[level]!.length - 1,
];
document.insert(path, [node]);
}
Color Conversion
Quill color formats are converted to AppFlowy format:
// Hex colors
final color = attributes?['color'] as String?;
if (color != null && color.startsWith('#')) {
attrs[AppFlowyRichTextKeys.textColor] = '0xFF${color.substring(1)}';
}
// RGBA colors
if (color != null && color.startsWith('rgba')) {
// Parse and convert to Flutter Color
}
Handling Special Cases
Multiline Text Inserts
The encoder handles text containing newlines:
// From quill_delta_encoder.dart:52-57
final texts = op.text.split('\n');
if (texts.length > 1) {
node.delta?.insert(texts[0]);
document.insert([index++], [node]);
node = paragraphNode(delta: Delta()..insert(texts[1]));
}
Indentation Without Lists
Indentation on regular paragraphs is converted to spaces:
// From quill_delta_encoder.dart:106-120
void _applyIndentIfNeeded(Node node, Map<String, dynamic> attributes) {
final indent = attributes[_indent] as int?;
final list = attributes[_list] as String?;
if (indent != null && list == null && node.delta != null) {
node.updateAttributes({
'delta': node.delta
?.compose(
Delta()
..retain(0)
..insert(' ' * indent),
)
.toJson(),
});
}
}
Limitations
Some Quill features are not yet supported during conversion:
- Font size and font family
- Text alignment (left, center, right, justify)
- Code blocks (inline code is supported)
- Images and embeds
- Custom attributes
Error Handling
The encoder only supports text insert operations:
if (op is TextInsert) {
// Handle text insertion
} else {
throw UnsupportedError('only support text insert operation');
}
Migration Guide
If you’re migrating from a Quill-based editor:
- Export your Quill content as Delta JSON
- Parse the JSON to a Delta object
- Use
quillDeltaEncoder.convert() to create an AppFlowy document
- Initialize your EditorState with the converted document
// Step 1: Get Quill Delta JSON from your Quill editor
final quillJson = quillEditor.getContents();
// Step 2: Convert to Delta object
final delta = Delta.fromJson(quillJson);
// Step 3: Convert to AppFlowy document
final document = quillDeltaEncoder.convert(delta);
// Step 4: Create EditorState
final editorState = EditorState(document: document);
Example: Complex Document
final json = r'''[
{"insert": "Project Tasks"},
{"attributes": {"header": 1}, "insert": "\n"},
{"insert": "Complete documentation"},
{"attributes": {"list": "checked"}, "insert": "\n"},
{"insert": "Review pull requests"},
{"attributes": {"list": "unchecked"}, "insert": "\n"},
{"insert": "Important", "attributes": {"bold": true, "color": "#FF0000"}},
{"insert": ": Deploy by Friday\n"}
]''';
final delta = Delta.fromJson(jsonDecode(json));
final document = quillDeltaEncoder.convert(delta);
final editorState = EditorState(document: document);
See Also