block_editor 0.0.4-dev.1
block_editor: ^0.0.4-dev.1 copied to clipboard
A Notion-inspired, block-based rich text editor for Flutter. Built from scratch with a plugin system, inline embeds, variables, tags, and export to JSON, Markdown, and HTML.
Changelog #
All notable changes to the block_editor package are documented here.
The format follows Keep a Changelog. This package adheres to Semantic Versioning.
0.0.4-dev.1 — 2026-04-02 #
Re-release of Phase 4 content with updated package README and fully working example app. No API changes from 0.0.3-dev.1.
Changed #
- Package
README.mdrewritten with full public API documentation, usage examples, and roadmap - Example app completed — demonstrates all built-in block types, formatting toolbar, slash command menu, block action menu, keyboard shortcuts, drag and drop, and read-only viewer mode
0.0.3-dev.1 — 2026-04-01 #
Phase 4 — Toolbar & Commands. 540 tests passing. API is unstable — breaking changes are expected before 1.0.0.
Added #
Keyboard Shortcuts
KeyboardShortcutHandler— centralised keyboard shortcut dispatcher, fully testable without the Flutter bindingModifierKeys— value object carryingcmd,shift,altbooleans; production callers useModifierKeys.fromHardware(), test callers construct directlyKeyboardShortcutHandler.handle(KeyEvent, ModifierKeys)— dispatches a key event and returns whether it was consumed
Formatting Toolbar
FormattingToolbar— context-sensitive floating toolbar appearing over any expanded text selection; never shown inreadOnlymode- Eight buttons: Bold, Italic, Underline, Strikethrough, Inline Code, Link, Text Color, Background Color
- Each button reflects active / inactive / mixed state across the selection with toggle semantics
- Display mode controlled by
BlockEditorWidget.toolbarBreakpoint— floats above selection anchor above threshold, pins to editor bottom below it - Color buttons delegate to
onColorPickerRequestedcallback when provided, otherwise open built-in 12-swatch palette popover
Slash Command Menu
SlashCommandMenu— data-driven block insertion menu triggered by/at the start of an empty block or after a space; never shown inreadOnlymode- Groups entries by
BlockPlugin.slashCommandGroup()— built-in order: Text, Headings, Lists, Media, Embeds, Advanced; external groups follow alphabetically - Real-time filtering as the user types; arrow key navigation; Enter or Tab confirms; Escape or Backspace-to-empty dismisses; mouse click selects
- On confirmation: empty triggering block is transformed to selected type; block with content gets a new block inserted below;
/and filter text removed
Block Action Menu
BlockActionMenu— five-action floating menu anchored to each block's drag handle; never shown inreadOnlymode- Actions: Delete Block, Duplicate Block, Turn Into (submenu), Move Up, Move Down
- Move Up disabled for first block; Move Down disabled for last block; all actions dispatch through
BlockController
BlockEditorWidget — new parameters
toolbarBreakpoint(double, default768.0) — width threshold in logical pixels controlling toolbar display modeonColorPickerRequested(Future<Color?> Function(Color? currentColor)?) — optional custom color picker callback; built-in 12-swatch palette used when null
BlockRegistry
pluginsgetter — returns all registeredBlockPlugininstances; used bySlashCommandMenuandBlockActionMenu
BlockController
duplicate(String blockId)— inserts a copy of the identified block immediately below it with a fresh UUID, preserving type, attributes, children, and delta
EditorEditingOperations — new methods
applyStrikethrough()— toggles strikethrough on expanded selection or stores as pending attribute on collapsed selectionapplyInlineCode()— toggles inline code on expanded selection or stores as pending attribute on collapsed selectionapplyAttributes(InlineAttributes)— applies arbitraryInlineAttributesto the expanded selection; used by toolbar for color applicationextendSelectionToLineStart(),extendSelectionToLineEnd()— extend selection focus to start or end of current blockextendSelectionToDocumentStart(),extendSelectionToDocumentEnd()— extend selection focus to first or last offset in documentextendSelectionWordLeft(),extendSelectionWordRight()— extend selection focus one word boundary, crossing block boundariesapplyBold(),applyItalic(),applyUnderline()— now also store pending attributes on collapsed selection, applied to next inserted character
Changed #
TextDelta.applyAttributes— toggle semantics added for boolean attributes (bold, italic, underline, strikethrough, inlineCode); if every op in the target range already has the attribute set it is removed, otherwise set on all ops; color and link attributes unaffected
Fixed #
- Background color (
InlineAttributes.backgroundColor) was stored correctly but never rendered;RichTextRenderernow reads and applies it alongside inline code background, with inline code taking priority InlineAttributes.copyWithsilently ignored null values causing toggle-off to never work;TextDelta.applyAttributesnow constructsInlineAttributes(...)directly so null correctly clears a field
Breaking Changes #
EditorEditingOperationsis no longerconst-constructible — it holds mutable pending attribute state; all construction sites useEditorEditingOperations(controller)withoutconstso no call site changes are required for existing consumers
0.0.2-dev.1 — 2026-03-20 #
First published pre-release. Covers Phase 1 (Document Model), Phase 2 (Rendering Engine), and Phase 3 (Block Plugin System). API is unstable — breaking changes are expected in future pre-release versions before 1.0.0.
Added #
Document Model (Phase 1)
BlockNode— typed content node withid,type,attributes, andchildrenBlockDocument— root container with orderedBlockNodelist, JSON serialisation and deserialisationTextDelta— inline rich text model as a list ofDeltaOpobjectsDeltaOpsealed class withTextOpsubtype carryingInlineAttributesInlineAttributes— bold, italic, underline, strikethrough, inline code, link, text color, background colorBlockController— document state manager with insert, delete, update, move, and transform operationsBlockTypes— typed constants for all built-in block type identifiersEditorSelection— sealed class replacingBlockSelectionfor cursor and range selection- Undo/redo stack with snapshot-based history
selectionStreamonBlockControlleralongside the document change stream
Rendering Engine (Phase 2)
BlockRenderer— stateless widget mappingBlockNodeto its Flutter widget viaBlockRegistryBlockEditorWidget— root editor widget with externalBlockControllerownership, keyboard events, focus, and scrollRichTextRenderer— convertsTextDeltainto aTextSpantree- Block widgets for Paragraph, H1, H2, H3, BulletList, NumberedList, Todo, Quote, and Divider
- Cursor rendering with public animation API
- Single-block and cross-block selection highlight
- Character-level editing operations in pure Dart
- Drag and drop block reordering with ghost preview and drop indicator
readOnlyflag onBlockEditorWidgetBlockEventsealed class as the universal block interaction contractCustomBlockEventwrapper subtype for external package event extensibility
Block Plugin System (Phase 3)
BlockPluginabstract interface —blockType,build(),serialize(),deserialize(), optionaltoolbarButton(),slashCommandItem(),slashCommandGroup()BlockRegistrywith publicregister(BlockPlugin)method — built-in blocks pre-registered internally- Per-block stream system via
BlockController.streamForBlock(String blockId) EditorEditingOperationsextended to operate onTextDelta.opspreserving inline formatting- IME and mobile soft keyboard input via
TextInputConnection - Built-in media block plugins: Image, Video, YouTube embed, File attachment, Code, Callout, Link
- Inline embed
DeltaOpsubtypes for variables and tags
0.0.1 — 2026-01-01 #
Initial mono-repo scaffold. No functional code. Repository structure, CI pipeline, Melos workspace configuration, and pubspec files only.