Skip to content

Commit 4bb8fbd

Browse files
fix(mothership): single stopped tail region and drain cleanup
1 parent cb63d01 commit 4bb8fbd

2 files changed

Lines changed: 13 additions & 6 deletions

File tree

apps/sim/app/workspace/[workspaceId]/home/components/message-content/message-content.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -983,17 +983,21 @@ function MessageContentInner({
983983
</div>
984984
</div>
985985
) : (
986-
// Stopped row and actions take the slot's place in the SAME render and
987-
// at the SAME extent (TAIL_REGION_CLASSES), so the swap is height-
988-
// neutral by construction — no reflow for the pinned scroller to absorb.
986+
// The settled tail takes the slot's place in the SAME render and at the
987+
// SAME extent (TAIL_REGION_CLASSES), so the swap is height-neutral by
988+
// construction — no reflow for the pinned scroller to absorb. A stopped
989+
// turn shares the ONE region (status left, actions right); stacking two
990+
// regions would double the tail and break neutrality.
989991
<>
990-
{lastSegment?.type === 'stopped' && (
992+
{lastSegment?.type === 'stopped' ? (
991993
<div className={cn(TAIL_REGION_CLASSES, 'gap-[8px]')}>
992994
<CircleStop className='size-[16px] flex-shrink-0 text-[var(--text-icon)]' />
993995
<span className='text-[14px] text-[var(--text-body)]'>Stopped by user</span>
996+
{actions && <div className='ml-auto'>{actions}</div>}
994997
</div>
998+
) : (
999+
actions && <div className={TAIL_REGION_CLASSES}>{actions}</div>
9951000
)}
996-
{actions && <div className={TAIL_REGION_CLASSES}>{actions}</div>}
9971001
</>
9981002
)}
9991003
</div>

apps/sim/app/workspace/[workspaceId]/home/components/mothership-chat/mothership-chat.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ export function MothershipChat({
306306
const scrollerPaddingRef = useRef<{ top: number; bottom: number } | null>(null)
307307
const sizerFloorAppliedRef = useRef(0)
308308
const floorDrainRafRef = useRef(0)
309+
useEffect(() => () => cancelAnimationFrame(floorDrainRafRef.current), [])
309310

310311
/**
311312
* Sizer floor while streaming: `scrollHeight` must never dip below the
@@ -340,12 +341,14 @@ export function MothershipChat({
340341
if (!floorActive) {
341342
if (sizerFloorAppliedRef.current === 0) return
342343
scrollerPaddingRef.current = null
343-
const pinned = el.scrollHeight - el.scrollTop - el.clientHeight <= 2
344344
cancelAnimationFrame(floorDrainRafRef.current)
345345
const drain = () => {
346346
const target = virtualizer.getTotalSize()
347347
const current = sizerFloorAppliedRef.current
348348
if (current === 0) return
349+
// Re-checked per frame: a user scrolling away mid-drain makes the
350+
// remaining shrink invisible, so finish instantly instead of clamping.
351+
const pinned = el.scrollHeight - el.scrollTop - el.clientHeight <= 2
349352
const next = Math.floor(current - Math.max(1, (current - target) * SMOOTH_CHASE_RATE))
350353
if (!pinned || next - target <= 1) {
351354
sizerFloorAppliedRef.current = 0

0 commit comments

Comments
 (0)