fix: prevent trainer label flash on carousel drag release
This commit is contained in:
@@ -94,30 +94,22 @@ export function TeamCarousel({ members, activeIndex, onActiveChange }: TeamCarou
|
||||
[]
|
||||
);
|
||||
|
||||
// Deferred index update — avoids calling parent setState during render
|
||||
// (onLostPointerCapture can fire during React reconciliation)
|
||||
const pendingIndexRef = useRef<number | null>(null);
|
||||
useEffect(() => {
|
||||
if (pendingIndexRef.current !== null) {
|
||||
onActiveChange(pendingIndexRef.current);
|
||||
pendingIndexRef.current = null;
|
||||
}
|
||||
});
|
||||
|
||||
const onPointerUp = useCallback(() => {
|
||||
if (!dragStartRef.current) return;
|
||||
const startIdx = dragStartRef.current.startIndex;
|
||||
const currentOffset = dragOffset;
|
||||
const wasDrag = Math.abs(currentOffset) > 10;
|
||||
const steps = wasDrag ? Math.round(currentOffset / CARD_SPACING) : 0;
|
||||
setDragOffset(0);
|
||||
if (steps !== 0) {
|
||||
pendingIndexRef.current = wrapIndex(startIdx - steps, total);
|
||||
}
|
||||
dragStartRef.current = null;
|
||||
isDraggingRef.current = false;
|
||||
pausedUntilRef.current = Date.now() + PAUSE_MS;
|
||||
}, [total, dragOffset]);
|
||||
if (steps !== 0) {
|
||||
// Update index and reset offset in the same batch so the old card
|
||||
// never becomes center for a frame (prevents label flash)
|
||||
onActiveChange(wrapIndex(startIdx - steps, total));
|
||||
}
|
||||
setDragOffset(0);
|
||||
}, [total, dragOffset, onActiveChange]);
|
||||
|
||||
// Compute interpolated style for each card
|
||||
const baseIndex = dragStartRef.current ? dragStartRef.current.startIndex : activeIndex;
|
||||
@@ -165,6 +157,8 @@ export function TeamCarousel({ members, activeIndex, onActiveChange }: TeamCarou
|
||||
? "none"
|
||||
: "all 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94)",
|
||||
isCenter: absDiff < 0.5,
|
||||
/** 1 at center, fades to 0 by absDiff=0.6 */
|
||||
centerOpacity: clamp(1 - absDiff / 0.6, 0, 1),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -228,10 +222,16 @@ export function TeamCarousel({ members, activeIndex, onActiveChange }: TeamCarou
|
||||
draggable={false}
|
||||
/>
|
||||
|
||||
{style.isCenter && (
|
||||
{style.centerOpacity > 0 && (
|
||||
<>
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black/80 via-black/10 to-transparent" />
|
||||
<div className="absolute bottom-0 left-0 right-0 p-5">
|
||||
<div
|
||||
className="absolute inset-0 bg-gradient-to-t from-black/80 via-black/10 to-transparent"
|
||||
style={{ opacity: style.centerOpacity }}
|
||||
/>
|
||||
<div
|
||||
className="absolute bottom-0 left-0 right-0 p-5"
|
||||
style={{ opacity: style.centerOpacity }}
|
||||
>
|
||||
<h3 className="text-lg font-bold text-white sm:text-xl drop-shadow-lg">
|
||||
{m.name}
|
||||
</h3>
|
||||
|
||||
Reference in New Issue
Block a user