Add .fitContent option for content growing to natural size#75
Conversation
Add MarkdownEditorConfiguration.heightBehavior (.scrolls default / .fitsContent). In .fitsContent the editor reports its content height to SwiftUI via sizeThatFits + ClampedScrollView.intrinsicContentSize, skips the viewport-fill inflation and bottom overscroll, and makes the inner scroll view inert (no scroller, wheel events forwarded) so an enclosing ScrollView/page scrolls instead of a nested inner scroller. The default .scrolls path is gated behind every new branch and is behavior-identical to before. Phase 1 of 2: config knob + static fit-to-content sizing. 15 new tests; swift build/test green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add .fitContent option for content growing to natural size
Remove tests that only duplicate existing coverage — no real assertions lost (134 -> 128 tests, all green): - fitsContentScrollableContentHeightEqualsBaseContent: tautological (scrollableContentHeight = base + 0 by definition) - fitsContentApplyManagedFrameSizeUsesExactContentHeight: duplicate of fitsContentNoInflation (same invariant, different number) - switchFromScrollsToFitsContentChangesDecision / switchFromFitsContentToScrollsChangesDecision: re-call the pure wantsVerticalScroller(for:) with inputs already covered by fitsContentAlwaysDisablesVerticalScroller + scrollsRespectsScrollersPolicy (a pure function has no 'switch' state) - widthChangeUpdatesHeightInReadingColumnMode: its 'width change' re-applies identical values (no actual change); duplicates readingWidthPreservedNoInflation - readingWidthEmptyDocStillHasPositiveHeight: near-duplicate of emptyDocHasPositiveHeight (readingWidth doesn't affect the assertion) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PR #75 (
|
| Action | .fitsContent |
Freeze? |
|---|---|---|
| Open / width-resize | full layout, O(n) | yes — the cost for huge docs |
| Typing | partial end-measure, ~0.15 ms, size-independent | no |
| Scrolling | no re-layout (giant view may add draw cost at extreme sizes) | shouldn't; verify in Release |
Guidance
- Use
.fitsContentfor small-to-medium inline content; keep.scrollsfor
large documents (virtualization). Off by default → zero impact when unused. - If
.fitsContentis ever needed on very large docs and Release is still slow,
the real fix is an engine change: report an estimated height
(lineCount × avgLineHeight) and refine lazily, restoring virtualization.
Test cleanup (committed on this branch)
Removed 6 redundant tests from HeightBehaviorTests.swift (134 → 128 tests, all
green) — duplicates only, no real coverage lost:
fitsContentScrollableContentHeightEqualsBaseContent— tautological.fitsContentApplyManagedFrameSizeUsesExactContentHeight— dup of
fitsContentNoInflation.switchFromScrollsToFitsContentChangesDecision/
switchFromFitsContentToScrollsChangesDecision— re-test the pure
wantsVerticalScroller(for:)with already-covered inputs.widthChangeUpdatesHeightInReadingColumnMode— its "width change" re-applies
identical values; dup ofreadingWidthPreservedNoInflation.readingWidthEmptyDocStillHasPositiveHeight— near-dup of
emptyDocHasPositiveHeight.
Method note
A headless perf benchmark (HeightBehaviorPerfTests.swift) and a Demo perf
harness (FPS via CADisplayLink + memory readout) were used during this
investigation and then removed — throwaway tooling, not part of this branch.
|
gj |
I wanted to use this control on a screen that already had a scroll view. Currently the control embeds its own scroll view, so I was stuck with a scrolling screen, with a second nested scrollable markdown notes section. Not great.
This change adds
.fitContentoption. The control grows to fit its content, so I can just scroll the containing page to scroll my markdown note. Doesn't work with the header pinning, but that's expected.Isolation: implemented as new and optional init option, off by default. Zero impact to existing API or existing users.
AI disclosure: this was all Claude Opus, I'm no swift UI expert. However I did read it, embed it in another app, and do manual UI tests. It's working great.