Toolbar and structure
You will add headings, bulleted and numbered lists, tasks, code, quotes, dividers, images and tables; a toolbar row above the document; and a button that edits the document from code.
Packages
yaml
dependencies:
vyuh_document_elements:
hosted: https://pub.vyuh.tech
version: ^0.19.3sh
flutter pub add vyuh_document_elements --hosted-url https://pub.vyuh.techvyuh_document_elements collects every first-party element and two ready configurations: notesConfiguration and documentConfiguration.
The code
dart
import 'package:flutter/material.dart' hide Table;
import 'package:vyuh_document/vyuh_document.dart';
import 'package:vyuh_document_editor/document_editor.dart';
import 'package:vyuh_document_elements/vyuh_document_elements.dart';
/// A pageless notes editor: headings, lists, tasks, code, images, quotes,
/// dividers and tables, with a toolbar row.
class NotesEditor extends StatefulWidget {
const NotesEditor({super.key});
@override
State<NotesEditor> createState() => _NotesEditorState();
}
class _NotesEditorState extends State<NotesEditor> {
late final controller = DocumentController(
notesConfiguration,
document: Document.of(notesConfiguration, [
Heading('Sprint notes'),
Paragraph('Select text to format it, or add a table below.'),
Table([
['Owner', 'Task'],
['Asha', 'Ship the release'],
]),
]).valueOrNull,
);
@override
void dispose() {
controller.close();
super.dispose();
}
/// Commands run from code go through the same history as typing.
void addRow() {
final table = controller.document.body.first<Table>();
final result = controller.run(InsertRow(table, at: 2)).then((_) {
// Address the new cell in the document as it is now.
final updated = controller.document.body.first<Table>();
return controller.run(SetText(updated.cell(row: 2, column: 1), 'Review'));
});
if (result case Failed(:final error)) debugPrint('$error');
}
@override
Widget build(BuildContext context) => Column(
children: [
TextButton(onPressed: addRow, child: const Text('Add a row')),
Expanded(
child: DocumentEditor(
controller: controller,
surface: const DocumentSurface.pageless(maxWidth: 720),
chrome: const EditorChrome.toolbar(Toolbar.standard),
),
),
],
);
}You see a pageless column up to 720 points wide with a toolbar: undo, redo, heading 1 and 2, the marks, link, bulleted and numbered lists, and table. Add a row inserts a table row and writes into its second cell.
Configurations filter everything
A toolbar part whose element is not configured never shows, and paste degrades what the configuration cannot hold: a table pasted into a rich-text field arrives as its cells' paragraphs.
Choose the toolbar parts
dart
const EditorChrome.toolbar(Toolbar([
UndoButton(),
RedoButton(),
HeadingButton(level: HeadingLevel.h2),
BoldButton(),
ItalicButton(),
LinkButton(),
ListButton(ordered: true),
TableButton(),
]));Toolbar.formatting and Toolbar.standard are ready-made sets. EditorChrome(toolbar: ..., bubble: ...) combines a row and a bubble.
Commands from code
Every edit, from a button or from your code, is a typed command:
| Command | Result |
|---|---|
InsertBlock(Paragraph('Hi'), after: ref) | Ref<Paragraph> of the new block |
InsertRow(table, at: 2) | Ref<Row> |
SetText(cell, 'Done') | void |
ToggleMark(Bold(), range) | void |
controller.run returns Done(value) or Failed(error); a failed command changes nothing. See Commands for the full catalog and Addressing for Ref, Position and Range.
Name clashes with Flutter
Table, Image and Divider are both Flutter widgets and Vyuh elements. Hide Flutter's in files that use the elements: import 'package:flutter/material.dart' hide Table;
Next
Step 3: a document editor moves to the editor runtime for images, fonts and a full action toolbar.