From 67f017a61702e80dd82d66eda37a6334f8dc23bd Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Wed, 8 Apr 2026 16:43:49 +0000 Subject: [PATCH] perf: move frame(maxWidth:) from LazyVStack content to ScrollView to fix 134s hang (LUM-740) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move .frame(maxWidth: VSpacing.chatColumnMaxWidth) and .frame(maxWidth: .infinity) from inside the ScrollView content (MessageListContentView) to the ScrollView itself (MessageListView). These modifiers compile to _FlexFrameLayout which calls sizeThatFits on children. When placed between ScrollView and LazyVStack, new message insertions trigger initialPlacement → motionVectors → measureEstimates over ALL ForEach items, defeating laziness entirely (O(n) where each cell is complex). Moving them outside the ScrollView removes _FlexFrameLayout from the scroll content measurement path. The ScrollView is a greedy container that accepts its proposed size without measuring content, so width constraints on its frame work correctly without triggering child measurement. Padding stays inside scroll content for correct insets. Visual alignment is preserved: chatColumnMaxWidth = chatBubbleMaxWidth + 2*xl, and the internal padding of xl on each side still yields chatBubbleMaxWidth for bubble content. Co-Authored-By: ashlee@vellum.ai --- .../vellum-assistant/Features/Chat/MessageListContentView.swift | 2 -- .../macos/vellum-assistant/Features/Chat/MessageListView.swift | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clients/macos/vellum-assistant/Features/Chat/MessageListContentView.swift b/clients/macos/vellum-assistant/Features/Chat/MessageListContentView.swift index b7c6cc70b11..3771785df82 100644 --- a/clients/macos/vellum-assistant/Features/Chat/MessageListContentView.swift +++ b/clients/macos/vellum-assistant/Features/Chat/MessageListContentView.swift @@ -284,8 +284,6 @@ struct MessageListContentView: View, Equatable { .disabled(!isInteractionEnabled) .padding(EdgeInsets(top: VSpacing.md, leading: VSpacing.xl, bottom: VSpacing.md, trailing: VSpacing.xl)) - .frame(maxWidth: VSpacing.chatColumnMaxWidth) - .frame(maxWidth: .infinity) .environment(\.bubbleMaxWidth, containerWidth > 0 ? min(VSpacing.chatBubbleMaxWidth, max(containerWidth - 2 * VSpacing.xl, 0)) : VSpacing.chatBubbleMaxWidth) diff --git a/clients/macos/vellum-assistant/Features/Chat/MessageListView.swift b/clients/macos/vellum-assistant/Features/Chat/MessageListView.swift index 34ce2fee79d..1bf03fb229a 100644 --- a/clients/macos/vellum-assistant/Features/Chat/MessageListView.swift +++ b/clients/macos/vellum-assistant/Features/Chat/MessageListView.swift @@ -116,6 +116,8 @@ struct MessageListView: View { .id(conversationId) .scrollContentBackground(.hidden) .scrollDisabled(messages.isEmpty && !isSending) + .frame(maxWidth: VSpacing.chatColumnMaxWidth) + .frame(maxWidth: .infinity) // Apply only to .initialOffset — where the scroll view starts // when first displayed (including .id() recreation on switch). // Deliberately NOT using the all-roles overload (.sizeChanges)