fix(issues): prevent sticky mini bar oscillation with height placeholder

When the agent live card collapses to sticky mode, its height drops from
~320px to ~40px. This layout shift caused content below to jump up,
re-triggering IntersectionObserver and creating an infinite loop.

Fix: capture the card's expanded height before collapsing, then set
minHeight on a wrapper div to preserve the space. Content below stays
put, sentinel stays out of view, no oscillation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Naiyuan Qing 2026-04-03 18:29:59 +08:00
parent 33140d4c5a
commit 9fb25f4543

View file

@ -112,8 +112,10 @@ export function AgentLiveCard({ issueId, agentName, scrollContainerRef }: AgentL
const [autoScroll, setAutoScroll] = useState(true);
const [cancelling, setCancelling] = useState(false);
const [isStuck, setIsStuck] = useState(false);
const [cardHeight, setCardHeight] = useState(0);
const scrollRef = useRef<HTMLDivElement>(null);
const sentinelRef = useRef<HTMLDivElement>(null);
const cardRef = useRef<HTMLDivElement>(null);
const seenSeqs = useRef(new Set<string>());
// Check for active task on mount
@ -237,7 +239,13 @@ export function AgentLiveCard({ issueId, agentName, scrollContainerRef }: AgentL
const observer = new IntersectionObserver(
(entries) => {
if (entries[0]) setIsStuck(!entries[0].isIntersecting);
if (!entries[0]) return;
const stuck = !entries[0].isIntersecting;
// Capture expanded height before collapsing to use as placeholder
if (stuck && cardRef.current) {
setCardHeight(cardRef.current.offsetHeight);
}
setIsStuck(stuck);
},
{ root, threshold: 0, rootMargin: "-40px 0px 0px 0px" },
);
@ -284,7 +292,10 @@ export function AgentLiveCard({ issueId, agentName, scrollContainerRef }: AgentL
{/* Sentinel — zero-height element that IntersectionObserver watches */}
<div ref={sentinelRef} className="mt-4 h-0 pointer-events-none" aria-hidden />
{/* Placeholder preserves card height when stuck, preventing layout shift */}
<div style={{ minHeight: isStuck && cardHeight ? cardHeight : undefined }}>
<div
ref={cardRef}
className={cn(
"rounded-lg border transition-all duration-200",
isStuck
@ -374,6 +385,7 @@ export function AgentLiveCard({ issueId, agentName, scrollContainerRef }: AgentL
)}
</div>
</div>
</div>
</>
);
}