fix: carousel image lightbox

This commit is contained in:
gosangam
2026-08-09 11:11:35 +05:30
parent df49e7afcc
commit baf36d3d67
4 changed files with 220 additions and 130 deletions
+6 -28
View File
@@ -41,6 +41,7 @@ import { postSourceHref, quoteCardBgStyle } from "./post-card-shared";
import { PostActionsFooter } from "./post-actions-footer";
import { PostCardMenu } from "./post-card-menu";
import { PostImageLightbox } from "./post-image-lightbox";
import { useTapGuard } from "./use-tap-guard";
import { FeedFollowButton } from "./feed-follow-button";
import { UpdateBackgroundModal } from "../update-background-modal";
import { MentionsDrawer } from "../mentions-drawer";
@@ -252,12 +253,9 @@ function ImageCarousel({
}) {
const [active, setActive] = useState(0);
const scrollerRef = useRef<HTMLDivElement>(null);
// Where the pointer went down, plus the scroller's position at that moment.
// Swiping the carousel and tapping a photo have to stay independent: the
// carousel scrolls natively (CSS scroll-snap), and browsers still fire a
// click after some swipe gestures. Comparing both the pointer travel AND
// whether the strip actually scrolled lets us drop those.
const tapStart = useRef({ x: 0, y: 0, scrollLeft: 0 });
// Swiping the carousel and tapping a photo have to stay independent — the
// strip scrolls natively, and browsers still fire a click after some swipes.
const { onPointerDown, wasTap } = useTapGuard(scrollerRef);
function onScroll(e: React.UIEvent<HTMLDivElement>) {
const el = e.currentTarget;
@@ -266,26 +264,6 @@ function ImageCarousel({
setActive(Math.round(el.scrollLeft / w));
}
function onPointerDown(e: React.PointerEvent) {
tapStart.current = {
x: e.clientX,
y: e.clientY,
scrollLeft: scrollerRef.current?.scrollLeft ?? 0,
};
}
/** True only for a genuine tap — barely any pointer travel and no scroll. */
function wasTap(e: React.MouseEvent) {
const moved =
Math.abs(e.clientX - tapStart.current.x) > 8 ||
Math.abs(e.clientY - tapStart.current.y) > 8;
const scrolled =
Math.abs(
(scrollerRef.current?.scrollLeft ?? 0) - tapStart.current.scrollLeft,
) > 4;
return !moved && !scrolled;
}
if (images.length === 1) {
// Single image: no scroller, so every click is unambiguously a tap.
return (
@@ -293,7 +271,7 @@ function ImageCarousel({
type="button"
onClick={() => onOpen(0)}
aria-label="View photo"
className="relative block w-full aspect-square bg-muted cursor-zoom-in outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset"
className="relative block w-full aspect-square bg-muted cursor-pointer outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset"
>
<Image
src={images[0].url}
@@ -328,7 +306,7 @@ function ImageCarousel({
}}
aria-roledescription="slide"
aria-label={`View photo ${i + 1} of ${images.length}`}
className="relative block w-full shrink-0 snap-start aspect-square bg-muted cursor-zoom-in outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset"
className="relative block w-full shrink-0 snap-start aspect-square bg-muted cursor-pointer outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset"
>
<Image
src={img.url}