Skip to content

Fix paragraph/heading blocks always reporting full offered width - #158

Closed
Ramon Ferreira (ramonfsk) wants to merge 4 commits into
microsoft:mainfrom
ramonfsk:fix-paragraph-hugging-width
Closed

Fix paragraph/heading blocks always reporting full offered width#158
Ramon Ferreira (ramonfsk) wants to merge 4 commits into
microsoft:mainfrom
ramonfsk:fix-paragraph-hugging-width

Conversation

@ramonfsk

Copy link
Copy Markdown
Contributor

Summary

fixes SingleBlockView's .paragraph/.heading cases always reporting the full offered width upward, which breaks any ancestor that hugs its content to a capped width (the standard SwiftUI pattern for chat bubbles).

SingleBlockView wrapped ParagraphView in HStack(spacing: 0) { ParagraphView(...); Spacer() }. the trailing Spacer() has no minLength, so it absorbs all leftover width from whatever the HStack is proposed — meaning the block reports the full proposed width upward regardless of how little the text actually needs. drop the wrapper entirely; render ParagraphView directly. this is safe because left-alignment already comes from the text itself (UITextView.textAlignment / NSTextView paragraph-style alignment on macOS), not from the removed HStack, and BlockView's outer VStack is already alignment: .leading.

turns out the bug is broader than "hugging" alone. the same Spacer() negotiation also constrains the width actually proposed to ParagraphView for text wrapping — so paragraphs wrapped one or more words earlier than the space available to them, even with no capped/hugging ancestor at all. re-recording the library's own existing snapshot fixtures after the fix shows the same effect in completely ordinary, full-bleed usage: e.g. "This is a paragraph with some text to render." wraps to one line instead of two now. text, formatting, and left-alignment are unaffected — only where lines break, always using more of the available width, never less.

Closes #157

Screenshots

testCitations and testCustomBlockSpacing, before (main) vs. after (this branch) — same text, same formatting, wrapping to fewer/wider lines:

before after
testCitations before testCitations after
testCustomBlockSpacing before testCustomBlockSpacing after

Validation

  • new BlockViewWidthHuggingTests: a short paragraph/heading proposed 300pt resolves to well under half that (via UIHostingController/NSHostingController.sizeThatFits(in:)), while a paragraph that needs to wrap still fills the proposed width — no regression to wrapping behavior
  • make test — full suite passes, including three pre-existing fixtures re-recorded for the reason above (testCitations, testCustomBlockSpacing, testMarkdownLists_uikit, iOS and macOS variants): diffed old vs. new pixel-by-pixel, confirmed text/formatting/alignment identical, only line-break position changed
  • confirmed downstream in a real consumer (Threadwire, a chat SDK) via a local SPM package override: short replies now hug their actual text width instead of filling to the chat bubble's cap; long, wrapping content is unaffected

OSS readiness

  • No secrets, internal URLs, private identifiers, or product-only service names were added.
  • Public docs, fixtures, or notices were updated if behavior or dependencies changed. (no doc-visible behavior change; this is a rendering-correctness fix)
  • Third-party dependency changes (adds, removes, version bumps) are intentional and reviewed. (no dependency changes)
  • Streaming/incomplete markdown behavior remains covered by fixtures or tests.

An unqualified Spacer() inside SingleBlockView's .paragraph/.heading HStack
absorbs all leftover width from whatever the HStack is proposed, so the block
always reports the full proposed width upward regardless of how little the
text actually needs - defeating any ancestor that hugs its content to a
capped width (e.g. a chat bubble). Render ParagraphView directly instead;
left-alignment already comes from UITextView.textAlignment and BlockView's
own leading VStack, not from the Spacer.

Draft issue writeup in ISSUE_DRAFT-paragraph-hugging-width.md - not filed
upstream yet, to be opened as an issue/PR in a future session.
BlockViewWidthHuggingTests proves the fix: a short paragraph/heading
now resolves to a width close to its actual text needs when proposed
more room than that (via UIHostingController/NSHostingController
sizeThatFits(in:)), while a paragraph that needs to wrap still fills
the proposed width - no regression to wrapping.

Re-recorded three pre-existing snapshot fixtures affected by the same
root cause: testCitations, testCustomBlockSpacing, and
testMarkdownLists_uikit each contain a paragraph that previously
wrapped one or more words earlier than the width actually available to
it, because the Spacer() in the old HStack constrained what width was
proposed to ParagraphView for wrapping - not just what was reported
back upward. Text, formatting, and left-alignment are pixel-identical;
only line-break position changed to use the full available width.
macOS references for these three fixtures still need re-recording via
the "Record macOS Snapshots" workflow in a follow-up commit.

Refs microsoft#157

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Same root cause and same fixtures as the iOS re-recording: text now
wraps using the full width actually available to it instead of a
narrower width caused by the old Spacer() HStack negotiation.

Refs microsoft#157

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes SingleBlockView paragraph/heading layout so those blocks no longer report the full proposed width upward (previously caused by an HStack { …; Spacer() } wrapper), enabling correct width-hugging behavior and more accurate text wrapping.

Changes:

  • Remove the HStack + Spacer() wrapper around .paragraph and .heading, rendering ParagraphView directly.
  • Add a new BlockViewWidthHuggingTests regression test suite to validate hugging vs. wrapping behavior.
  • Add a root-level issue draft markdown file (likely unintended to ship with the library PR).

Reviewed changes

Copilot reviewed 3 out of 21 changed files in this pull request and generated 3 comments.

File Description
Sources/MarkdownText/UI/BlockView.swift Removes the HStack/Spacer wrapper for headings/paragraphs and documents the rationale.
Tests/MarkdownTextTests/BlockViewWidthHuggingTests.swift Adds regression tests measuring resolved width via hosting controllers under a capped proposal.
ISSUE_DRAFT-paragraph-hugging-width.md Adds a draft issue write-up to the repo root (appears unrelated to shipping code/tests).

Comment thread Tests/MarkdownTextTests/BlockViewWidthHuggingTests.swift Outdated
Comment thread Sources/MarkdownText/UI/BlockView.swift Outdated
Comment thread ISSUE_DRAFT-paragraph-hugging-width.md Outdated
- remove the unused Foundation import from BlockViewWidthHuggingTests
- mention NSTextView's paragraph-style alignment alongside UITextView
  in SingleBlockView's comment, since the claim applies to both
  platforms, not just iOS
- remove ISSUE_DRAFT-paragraph-hugging-width.md, a local planning note
  that shouldn't have shipped with the library/test diff

Refs microsoft#157

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 20 changed files in this pull request and generated no new comments.

@junyan72

Copy link
Copy Markdown
Contributor

Thanks for the PR! this has been fixed in #162

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: paragraph/heading blocks always report full offered width, breaking width-hugging containers

3 participants