Chevron Button Behavior

Nucleic-Session: 8BCB521F-EFDD-48A4-B1E8-1E0499B25516
Co-authored-by: Nucleic <[email protected]>
This commit is contained in:
2026-07-06 17:26:09 -07:00
co-authored by Nucleic
parent 2b70952928
commit e1bb0f0772
@@ -556,6 +556,17 @@ struct TranscriptList: View {
guard transcriptSettling, transcriptContentHeight > 0 else { return }
try? await Task.sleep(for: .milliseconds(80))
if Task.isCancelled { return }
// Pin to the true bottom before opening the gate. The settling layout lands a
// hair off the bottom, so the passive `.defaultScrollAnchor` alone leaves the
// scroll geometry reading "not at bottom" — and that stale reading latches
// `onScrollGeometryChange`'s tracked value at `false` while the gate above holds
// `isScrolledToBottom` at `true`. Because the callback only fires on a *change*,
// the user's first real scroll-up (still `false`) then never fires it: the chevron
// never appears and live output keeps yanking the view to the bottom, until a
// down-then-up round-trip finally re-emits the change. An explicit pin nudges the
// offset the last hair, forcing a fresh "at bottom" emission that re-syncs the
// tracker with the gate. Mirrors the Mac's reveal pin.
scrollToEnd(proxy, animated: false)
transcriptSettling = false
}
// Coalescing means item count lags event count; key the autoscroll on the raw stream