editorjs_flutter 0.5.0-beta.1
editorjs_flutter: ^0.5.0-beta.1 copied to clipboard
Flutter viewer and editor widgets for the EditorJS JSON schema. Supports 14 built-in block types with a Clean Architecture extension point for custom blocks.
0.5.0-beta.1 - 2026-03-25 — Publication readiness #
New API #
EditorController.fromJson(String jsonString, {BlockTypeRegistry? typeRegistry})— creates a controller pre-populated from an existing EditorJS JSON string; gracefully handles invalid JSON.
Package metadata #
pubspec.yaml— updated description and addedtopics(editor, rich-text, editorjs, content).example/directory added — two-tab demo app showingEditorJSView(viewer tab) andEditorJSEditor(editor tab).
CI / CD #
.github/workflows/ci.ymladded — runsflutter analyze+flutter test --coverageon every PR and push tomaster; enforces ≥ 80 % line coverage viaVeryGoodOpenSource/very_good_coverage@v3; uploads report to Codecov.
Contribution rules #
- 80 % minimum test coverage enforced in CI — PRs that drop below this threshold cannot be merged.
CLAUDE.mdupdated with contribution rules, refreshed block types table, and updated backlog.
Tests #
- Added
test/unit/block_entities_test.dart—toJson()andtypegetter for all 14 block entities. - Added
test/unit/html_style_builder_test.dart—HtmlStyleBuilder.build()with various configs. - Extended
test/widget/renderers_test.dart— paragraph, quote, list (flat/ordered/nested), table, image, linkTool, raw. - Added
test/widget/editorjs_view_test.dart— integration tests for the full parse → render pipeline. - Added
test/widget/editorjs_editor_test.dart— editor + block controls +fromJsonround-trip. - Added
test/widget/toolbar_test.dart— toolbar button interactions and hyperlink dialog. - Added
test/widget/block_editors_test.dart— individual editor widgets (paragraph, list, checklist, table, image, header, quote, warning, code).
0.4.0 - 2026-03-25 — Phase 4: Quality & Safety #
Null-safety hardening #
JsonDocumentSource.parse()now wrapsjsonDecodein try/catch — invalid JSON returns an emptyBlockDocumentinstead of throwing.HeaderMapper—levelfield usesis intguard instead of a bareas int?cast.ImageMapper—fileobject and all threeboolfields (withBorder,stretched,withBackground) use safe type checks.AttachesMapper—fileobject usesis Mapguard;sizehandles bothintandnum(double) via switch expression.EmbedMapper—widthandheighthandle bothintandnumvia switch expression.LinkToolMapper—imagesub-map usesis Mapguard.TableMapper—withHeadingsusesis boolguard.ChecklistMapper—checkedusesis boolguard.
Unknown block type logging #
JsonDocumentSourceemits adart:developerlogentry (name: 'EditorJSFlutter') when an unknown block type is silently dropped during parsing.
Tests (91 total) #
test/unit/html_sanitizer_test.dart(9 tests) — script tags, iframes, event handlers, edge cases.test/unit/mappers_test.dart(46 tests) — all 14 mappers; happy path, missing fields, wrong-type fields.test/unit/editor_controller_test.dart(17 tests) — all mutations, full undo/redo state machine.test/unit/json_document_source_test.dart— parse, unknown-type drop, invalid JSON, round-trip.test/widget/renderers_test.dart(9 tests) — header, delimiter, code, warning, checklist, embed, attaches.
0.3.0 - 2026-03-25 — Phase 3: Editor features #
Undo / redo #
EditorControllermaintains a capped (50-entry) history stack.canUndo/canRedoboolean getters,undo()/redo()methods.- History recorded on structural operations —
addBlock,insertBlock,removeBlock,moveBlock,clear. Live text edits viaupdateBlockdo not pollute the history. - Toolbar exposes Undo and Redo buttons that disable automatically when no history is available.
Per-block controls #
- Every block in
EditorJSEditoris now wrapped with three icon buttons: Move up (↑), Move down (↓), Delete (×). - Move-up is disabled on the first block; move-down is disabled on the last block.
- Delete emits
removeBlock, which is immediately undoable.
Inline formatting for paragraph blocks #
ParagraphEditorshows an inline format bar when the field is focused.- Six format actions: Bold (
<b>), Italic (<i>), Underline (<u>), Strikethrough (<s>), Inline code (<code>), Highlight (<mark>). - Applies tags around the current text selection; inserts empty tags with cursor between them when nothing is selected.
- Raw HTML stored in
ParagraphBlock.htmland rendered byflutter_htmlin the viewer.
Bug fix #
- Replaced deprecated
Color.withOpacity()withColor.withValues(alpha:)inQuoteRenderer.
0.2.1 - 2026-03-25 — Viewer completeness: embed, linkTool, attaches, raw #
New block types (viewer only) #
embed— tappable card showing service name, source URL, and optional caption; opens URL viaurl_launcher.linkTool— link preview card with thumbnail, title, description, and URL; opens link viaurl_launcher.attaches— file download card with type-specific icon, file size, andurl_launcherdownload action.raw— raw HTML content rendered throughflutter_htmlwith fullHtmlSanitizerprotection.
Cross-cutting renderer improvements #
- Extracted
HtmlStyleBuildershared utility — appliesdefaultFonttoflutter_htmlbodystyle and all CSS tag overrides, eliminating duplicate helpers across renderers. - Applied
HtmlSanitizer.sanitize()toQuoteRendererandListRenderer(HTML content fields). ImageRenderercaption now respectsstyleConfig.defaultFont.
Exports #
- All four new block entity classes (
EmbedBlock,LinkToolBlock,AttachesBlock,RawBlock) exported from the public barrel file.
0.2.0 - 2026-03-25 — Phase 2: Viewer & editor completeness #
New block types (viewer + editor) #
quote— blockquote with optional caption and left/center/right alignment.code— monospace code block with horizontal scroll, selectable text, and a copy-to-clipboard button.checklist— checkbox list with checked/unchecked state; strikethrough rendered on checked items.table— 2-D table with optional heading row, horizontal scroll, and add/remove row & column controls in the editor.warning— highlighted alert box with title and message fields.
Nested list support #
ListBlockitems are nowListItemobjects with a recursiveitemsfield.ListMapperhandles both flat string items (@editorjs/list) and nested object items (@editorjs/nested-list) transparently.ListRendererrenders nested items with indentation per depth level.
HTML sanitization #
- Added
HtmlSanitizerutility in the data layer that strips<script>,<iframe>, andon*event handler attributes before passing HTML toflutter_html. - Applied in
ParagraphRendererand will apply to any renderer that callsHtmlSanitizer.sanitize().
Toolbar #
- Added toolbar buttons for all new block types: Quote, Code, Checklist, Table, Warning.
Exports #
- All five new block entity classes are exported from the public barrel file.
0.1.0 - 2026-03-25 — Clean Architecture refactor (breaking) #
This release is a full architectural rewrite. The public API has changed. See the migration notes below.
Breaking changes #
EditorJSViewparameter renamed:editorJSData→jsonData,styles→config(acceptsEditorConfig).EditorJSEditornow requires anEditorControllerpassed viacontroller:.- Old
src/model/andsrc/widgets/packages removed entirely.
Architecture #
- Adopted Clean Architecture with three strict layers:
domain,data,presentation. Dependencies flow inward only;domainhas zero Flutter imports. - Applied SOLID principles throughout: one class per block type (SRP), block registry for extensibility without modifying core files (OCP), all renderers/editors implement typed abstract bases (LSP/DIP).
- New block type registry pattern: register custom block types at runtime via
BlockTypeRegistryandBlockRendererRegistrywithout touching any package file.
New: EditorController #
- Replaces the previous
List<Widget>anti-pattern in the editor. - Holds
List<BlockEntity>as the source of truth. - Exposes
getContent()→ EditorJS-compliant JSON string (previously impossible). - Zero-arg factory
EditorController()wires the default serializer automatically. - Full block management API:
addBlock,insertBlock,updateBlock,removeBlock,moveBlock,clear.
New: domain entities #
BlockEntity— abstract base class for all block types.BlockDocument— root document entity with fulltoJson()serialization.StyleConfig/CssTagConfig— styling configuration entities replacing old JSON-only models.- Typed block entities:
HeaderBlock,ParagraphBlock,ListBlock,DelimiterBlock,ImageBlock— each owns only its relevant fields and serializes itself.
New: data layer #
BlockMapper<T>— abstract interface for deserializing a block type from EditorJS JSON.- Five concrete mappers (
HeaderMapper,ParagraphMapper,ListMapper,DelimiterMapper,ImageMapper) with safe, non-throwing parsing. BlockTypeRegistry— pre-registered with all built-in mappers; callers call.register()for custom blocks.JsonDocumentSource— implementsDocumentRepository; unknown block types are silently skipped (never throws on unrecognized data).
New: presentation layer #
BlockRenderer<T>/BlockEditor<T>— abstract base widgets for custom block authors.BlockRendererRegistry— maps type strings to renderer/editor builder functions.EditorConfig— single configuration object accepted by bothEditorJSViewandEditorJSEditor.- Five renderer widgets: fully stateless, receive an immutable entity.
- Five editor widgets: push updates upward via
ValueChanged<T>callback; no direct parent coupling. EditorJSToolbar— decoupled from editor widget; communicates exclusively throughEditorController.- Image renderer now respects
caption,withBorder,stretched, andwithBackgroundfields. - Image load errors show a placeholder widget instead of crashing.
Dependency upgrades #
- Dart SDK constraint:
>=2.14.0 <3.0.0→>=3.0.0 <4.0.0 - Flutter constraint:
>=2.10.0→>=3.10.0 flutter_html:^2.2.1→^3.0.0-beta.2(API breaking:Style.paddingnow usesHtmlPaddings)image_picker:^0.8.6→^1.0.0url_launcher:^6.1.6→^6.2.0
Bug fixes #
- Replaced deprecated
launch()withlaunchUrl(Uri.parse(...))in toolbar. - Replaced deprecated
MaterialStatePropertywithWidgetStateProperty. - Fixed
stretchedfield never being assigned in the oldEditorJSBlockData.fromJson. - Removed duplicate
toolbar.dartimport ineditor.dart. - Fixed
MyHomePageconstructor to useKey?andrequired this.title(null safety). - Removed dead toolbar buttons (quote, list) that previously rendered with no functionality.
Migration guide #
// Before
EditorJSView(editorJSData: json, styles: stylesJson)
// After
EditorJSView(jsonData: json, config: EditorConfig(styleConfig: styleConfig))
// Before — editor had no save mechanism
EditorJSEditor()
// After — create a controller, pass it in, call getContent() to export
final controller = EditorController();
EditorJSEditor(controller: controller)
final json = controller.getContent();
0.0.5 Links support #
- Now you may add links in the editor. Just set the name and the url to set. NOTE: Right now is a basic implementation. I'll make it adhoc to EditorJS standard later
0.0.4 Image, text block and horizontal ruler insertion completed #
- You may use image insertion from camera and gallery. You must give permissions from your device for enabling it. Also, now you can create new text blocks and horizontal rulers. Soon you'll be able to change header on each block.
0.0.3 Added Toolbar #
- The toolbar scaffolding is ready. You may check it out in the Demo.
0.0.2 Added Styles for Paragraphs #
- Now you can add a paragraph with some styles.
0.0.1 Initial Release #
- The Viewer has been completed with the basic structures of an EditorJS JSON file.