-
Notifications
You must be signed in to change notification settings - Fork 88
perf(chat): use FixedWidthLayout for centeredChatColumn (LUM-1276) #29231
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -529,17 +529,29 @@ struct ChatView: View { | |
| ) | ||
| } | ||
|
|
||
| /// Centers chat chrome to the same fixed transcript width using _FrameLayout | ||
| /// rather than nested max-width flex frames. | ||
| /// Centers chat chrome at the chat-column width using `FixedWidthLayout`. | ||
| /// | ||
| /// `FixedWidthLayout` returns `nil` from `explicitAlignment` and places its | ||
| /// child via a `UnitPoint` anchor rather than alignment guides, so it acts | ||
| /// as a barrier to parent-initiated alignment queries on the subtree. The | ||
| /// inner `HStack { Spacer; content; Spacer }` reproduces the horizontal | ||
| /// `.center` positioning that `.frame(width:)` applied to non-filling | ||
| /// content; flexible content (anything with `.frame(maxWidth: .infinity)` | ||
| /// or an internal `Spacer`) collapses the inner spacers to zero and | ||
| /// occupies the full column width. | ||
| @ViewBuilder | ||
| private func centeredChatColumn<Content: View>( | ||
| width: CGFloat, | ||
| @ViewBuilder content: () -> Content | ||
| ) -> some View { | ||
| HStack(spacing: 0) { | ||
| Spacer(minLength: 0) | ||
| content() | ||
| .frame(width: width) | ||
| HStack(spacing: 0) { | ||
| Spacer(minLength: 0) | ||
| content() | ||
| Spacer(minLength: 0) | ||
| } | ||
| .fixedWidth(width) | ||
|
Comment on lines
+549
to
+554
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚩 Existing MessageListView fixedWidth usage pattern differs from new centeredChatColumn pattern In Was this helpful? React with 👍 or 👎 to provide feedback.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed — the inconsistency is real. Follow-up #29232 brings |
||
| Spacer(minLength: 0) | ||
| } | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔴 centeredChatColumn inner HStack+Spacer wrapping causes flexible content to compete with spacers instead of filling full width
The old
centeredChatColumnapplied.frame(width: width)directly to content, which unconditionally constrained the content to exactlywidthpixels — both for fixed-size content (centered via default.centeralignment) and for flexible content (proposedwidthand filling it). The new implementation wraps content inHStack(spacing: 0) { Spacer(minLength: 0); content(); Spacer(minLength: 0) }.fixedWidth(width), which proposeswidthto the inner HStack. The inner HStack then distributes that width among three children: twoSpacer(minLength: 0)and the content. For fixed-size content this correctly centers it (spacers expand equally). However, for flexible content — views that expand to fill available space — the content now competes with the two spacers for surplus space rather than being directly constrained towidth.Multiple callers pass flexible content:
CreditsExhaustedBanneruses.frame(maxWidth: .infinity, alignment: .leading)(ChatErrorToastView.swift:223)DiskPressureBannerhasSpacer(minLength:)in its HStack (ChatErrorToastView.swift:263)MissingApiKeyBanneruses.frame(maxWidth: .infinity)(ChatErrorToastView.swift:405) andSpacer()(ChatErrorToastView.swift:384)ComposerSection→ComposerViewuses.frame(maxWidth: .infinity)(ComposerView.swift:332)HStack { Spacer; Icon; Text; Spacer }(ChatView.swift:436)The docstring claims flexible content "collapses the inner spacers to zero and occupies the full column width," but this depends on undocumented SwiftUI HStack surplus-distribution behavior. If the surplus is shared equally among all flexible children (which is the standard understanding of HStack layout), banners and the composer would render narrower than the intended column width — a visible layout regression.
Prompt for agents
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Confirmed and addressed in follow-up #29232. The PR was merged before the fix landed, so the change is on a separate branch.
You're right that relying on HStack surplus distribution is undocumented. The follow-up adopts the
MessageListView.swift:147-182shape —.fixedWidth(width)applied directly tocontent(), no inner Spacer wrapper. Five of the sixcenteredChatColumncallers are horizontally flexible and fill the column on their own;CompactionCircuitOpenBanneris the lone natural-width caller and gets an explicitHStack { Spacer; banner; Spacer }wrap at its call site to preserve centering. Resolved.