mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
fix(composer): keep strip edge fades live when pill content grows after a resize
The overflow-fade hook resize-observes the scroller and its content wrapper, but the wrapper was a min-w-0 flex item: under a narrow container it collapsed to the scroller's content width, so the shrink-0 pill slots overflowed it invisibly. When a pill's deferred label ticker swapped in a longer label AFTER the resize settled, scrollWidth grew without resizing any observed element — no ResizeObserver callback, and the edge fades stayed stale (missing) until a manual scroll. Caught by the "narrow strip scrolls horizontally with edge fades" e2e spec, which failed deterministically because label swaps are intentionally deferred until slot layout settles. - BotActivityBar.tsx: give the scroller's content wrapper min-w-max on a multi-item strip so its border box always tracks content size and every late growth fires the ResizeObserver; keep min-w-0 for the lone-item case so a single pill/typing group still shrinks to fit (shrinkToFit) instead of overflowing into scroll - Side effect: pills no longer visually compress below their natural width inside a constrained strip (the collapsed wrapper was squeezing them); they keep readable widths and the strip scrolls as designed - Document the min-w-max dependency at the ResizeObserver in useStripOverflowFades so the wrapper's sizing isn't "simplified" back into a stale-fade regression Verified: all 13 activity/pill/typing specs in channels.spec.ts pass (including the previously failing narrow-strip fade spec and the new typing-inside-strip spec), plus both channel-composer-overflow specs. Co-authored-by: Taylor Ho <taylorkmho@gmail.com> Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
This commit is contained in:
@@ -105,7 +105,11 @@ function useStripOverflowFades(
|
||||
const observer = new ResizeObserver(updateFades);
|
||||
observer.observe(node);
|
||||
// The content wrapper is the scroller's only child; observing it catches
|
||||
// overflow changes that don't touch the scroller's own box.
|
||||
// overflow changes that don't touch the scroller's own box. This relies
|
||||
// on the wrapper being min-w-max (multi-item strip): if it could
|
||||
// collapse to the scroller's width, content growing INSIDE it (label
|
||||
// tickers swap after a resize settles) would change scrollWidth without
|
||||
// resizing any observed element, leaving the fades stale.
|
||||
const content = node.firstElementChild;
|
||||
if (content !== null) {
|
||||
observer.observe(content);
|
||||
@@ -602,7 +606,19 @@ export function BotActivityComposerAction({
|
||||
onScroll={updateFades}
|
||||
ref={scrollerRef}
|
||||
>
|
||||
<div className="flex min-w-0 items-center gap-1.5">
|
||||
<div
|
||||
// The overflow-fade hook resize-observes this wrapper as its proxy
|
||||
// for content size. min-w-max keeps it from collapsing to the
|
||||
// scroller's width (it is a shrinkable flex item), so late content
|
||||
// growth — label tickers swap AFTER a resize settles — still
|
||||
// changes an observed box and refreshes the fades. A lone item
|
||||
// instead gets min-w-0 so it can shrink with the container
|
||||
// (shrinkToFit) rather than overflow into scroll.
|
||||
className={cn(
|
||||
"flex items-center gap-1.5",
|
||||
itemCount === 1 ? "min-w-0" : "min-w-max",
|
||||
)}
|
||||
>
|
||||
<AnimatePresence initial={false}>
|
||||
{orderedAgents.map((agent) => (
|
||||
<AnimatedPillSlot
|
||||
|
||||
Reference in New Issue
Block a user