feat(editor): support for dynamic height - #41
Open
CatHood0 wants to merge 18 commits into
Open
Conversation
- HeightCache: O(1) sparse index→height map with index-shift on insert/delete - DynamicHeightConfig: minHeight, defaultBlockHeight, resizeDebounce - DynamicHeightController: orchestrates cache, exposes currentHeight, receives mutations from EditorState.apply() - BlockHeightReporter: mixin for block State classes; reports RenderBox height after layout - DynamicHeightLayout: ConstrainedBox(minHeight) + Column(mainAxisSize.min); replaces PageBlockComponent when dynamicHeight active - NovidentEditor: accepts dynamicHeightConfig / dynamicHeightController; skips ScrollServiceWidget - EditorState.apply(): notifies NodesInserted/NodesRemoved/TextChanged to controller - All 9 block components modified to include BlockHeightReporter mixin - 90 tests covering cache, config, controller, reporter, layout, integration, and growth scenarios
…validation - Overlay now wrapped in IntrinsicHeight when dynamicHeight active - No more SizedBox fallback or defaultHeight estimates - HeightCache.invalidateRange preserves old heights instead of reverting to defaultHeight, preventing one-frame overflow during growth - reportHeight skips unchanged check when block is dirty (invalidated) - 92 tests pass with zero overflow assertions
- DocumentContentStore: add multiEditDirectoryId ValueNotifier - DirectoryTile: right-click → context menu with 'Modo múltiple' - MultiEditorView: scrollable list of editors per file in directory (filename title + divider + NovidentEditor with dynamicHeight) - DesktopView: ValueListenableBuilder switches to MultiEditorView when dirId is set
…torView - ScrollServiceWidget no longer skipped — keeps Provider<EditorScrollController> intact for SelectionServiceWidget (follows original AppFlowy pattern) - MyEditor accepts optional dynamicHeightConfig parameter - MultiEditorView redesigned to match EditorPane exactly: white sheet (maxWidth 750, shadows, rounded), DocumentSession per file, status bar (close button only, no vim/word count/zen) - _FileSheet uses same DocumentSession + MyEditor pattern as EditorPane
getVisibleNodes returned empty list when visibleRangeNotifier stayed at (-1,-1) — the default state in dynamic height mode (no virtual scroll list to update the range). DesktopSelectionService.getNodeInOffset used this to locate tapped nodes, and with empty results selection could never start (no cursor, no selection, no interaction). Now returns all root children when the range is invalid, matching the semantics of dynamic height where every block is always visible. Added EditorState.getVisibleNodes test (5 cases) for regression.
IntrinsicHeight runs a full double-layout pass (O(N²)) which becomes prohibitively slow with 5000+ words across multiple paragraphs. Now IntrinsicHeight only runs on the very first frame (before any block has been measured). Once the HeightCache has real measurements (hasMeasuredBlocks=true), the editor switches to SizedBox with the cached currentHeight — O(1) rebuilds on every subsequent frame. The controller listener (_onDynamicHeightChanged) uses post-frame callbacks to avoid setState-during-build from didChangeDependencies.
Frame 1 (no cache): Column + IntrinsicHeight → measures all blocks. Frame 2+ (cache ready): ListView.builder(shrinkWrap:false, NeverScroll) → virtualizes blocks, only builds visible children. Combined with SizedBox(currentHeight) optimization from _NovidentEditorState. 92/97 tests pass. 5 compilation errors to investigate.
This reverts commit a73544e.
…nd state reporting
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
I'll add later the description of this feature
What I'm working on by now:
Scrollable, so, there's no way that theEditorStatecan handle auto-scroll service events automatically)Current State
Grabacion.de.pantalla.desde.2026-08-25.19-52-41.mp4
Knowed limitation
The perfomance is the issue that I couldn't find the solution. Since every block requires to update it's sizes, its really difficult to make the editor not being re-renderized everytime that keystroke event modifies node content.
As you see here, trying to use this "dynamic" mode, makes imposible using the editor (I don't do nothing, and it crashes. This video is running in a low end PC, with the release mode):
Grabacion.de.pantalla.desde.2026-08-25.19-58-01.mp4