From 41eb4d7f0d51cce786b915c6d6542c6e4f1ae37b Mon Sep 17 00:00:00 2001 From: StuBehan Date: Wed, 1 Jul 2026 16:52:37 +0100 Subject: [PATCH] fix(tickets): scroll viewport on cmd+up/down jump MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Tickets list watched outcomeSelectedIndex and scrolled to a separately-captured selectedRowID that lagged one keypress behind — so cmd+up/down moved the selection but not the viewport until the next arrow press. Watch selectedRowID directly and scroll to the id onChange delivers, mirroring the Sessions tab. Co-Authored-By: Claude Opus 4.8 (1M context) --- panel/OutcomesView.swift | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/panel/OutcomesView.swift b/panel/OutcomesView.swift index aefb6c9..70c5c36 100644 --- a/panel/OutcomesView.swift +++ b/panel/OutcomesView.swift @@ -94,14 +94,21 @@ struct OutcomesView: View { } .frame(maxWidth: .infinity, maxHeight: .infinity) .scrollIndicators(.visible) - .onChange(of: nav.outcomeSelectedIndex) { _ in - guard let selectedRowID else { return } + // Watch the resolved row id, not the raw index, and scroll to + // the id onChange hands us. Reading a separately-derived + // `selectedRowID` capture here lagged the viewport one keypress + // behind the selection — invisible when stepping ±1 (the row + // stays near the viewport) but obvious on a ⌘↑/↓ jump, where the + // pane didn't move until the next press. Mirrors the Sessions + // tab's onChange(of: selectedPID) pattern. + .onChange(of: selectedRowID) { newID in + guard let newID else { return } // Snap, don't animate. With key-repeat on a long list the // 0.15s animations piled up, the scroll lagged the // selection, then settled with an upward snap — the // "bounce". Instant scroll keeps the selection pinned and // the viewport tracking it smoothly. - proxy.scrollTo(selectedRowID, anchor: .center) + proxy.scrollTo(newID, anchor: .center) } } }