From dcc2d46544013406a08caab9b48c657655e93c91 Mon Sep 17 00:00:00 2001 From: vineyardbovines Date: Wed, 1 Apr 2026 15:23:59 -0400 Subject: [PATCH] web click n drag --- src/components/images/Gallery/index.tsx | 9 +++ src/components/images/Gallery/index.web.tsx | 65 ++++++++++++++++++++- 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/src/components/images/Gallery/index.tsx b/src/components/images/Gallery/index.tsx index 818dd6ca80..2321651766 100644 --- a/src/components/images/Gallery/index.tsx +++ b/src/components/images/Gallery/index.tsx @@ -171,6 +171,15 @@ export function Gallery({ horizontal pagingEnabled={false} showsHorizontalScrollIndicator={false} + snapToOffsets={images.reduce((offsets, image, i) => { + const prev = + i === 0 + ? 0 + : offsets[i - 1] + getItemWidth(images[i - 1]) + ITEM_GAP + offsets.push(prev) + return offsets + }, [])} + snapToAlignment="start" decelerationRate="normal" style={{ width: bleed ? windowWidth : containerWidth + QUOTE_PADDING * 2, diff --git a/src/components/images/Gallery/index.web.tsx b/src/components/images/Gallery/index.web.tsx index cbc531388d..b92a99f546 100644 --- a/src/components/images/Gallery/index.web.tsx +++ b/src/components/images/Gallery/index.web.tsx @@ -100,6 +100,60 @@ export function Gallery({ } const currentScrollX = useRef(0) + // Click-and-drag scrolling + const isDragging = useRef(false) + const dragStartX = useRef(0) + const dragScrollStart = useRef(0) + const hasDragged = useRef(false) + const scrollNodeRef = useRef(null) + + const onMouseDown = (e: React.MouseEvent) => { + const node = scrollNodeRef.current + if (!node || e.button !== 0) return + isDragging.current = true + hasDragged.current = false + dragStartX.current = e.clientX + dragScrollStart.current = node.scrollLeft + node.style.scrollBehavior = 'auto' + node.style.scrollSnapType = 'none' + node.style.cursor = 'grabbing' + node.style.userSelect = 'none' + } + + const onMouseMove = (e: React.MouseEvent) => { + if (!isDragging.current) return + const node = scrollNodeRef.current + if (!node) return + const dx = e.clientX - dragStartX.current + if (Math.abs(dx) > 3) { + hasDragged.current = true + } + node.scrollLeft = dragScrollStart.current - dx + } + + const onMouseUp = () => { + if (!isDragging.current) return + isDragging.current = false + const node = scrollNodeRef.current + if (!node) return + node.style.scrollBehavior = 'smooth' + node.style.scrollSnapType = 'x proximity' + node.style.cursor = '' + node.style.userSelect = '' + } + + const onScrollViewRef = (ref: ScrollView | null) => { + scrollRef.current = ref + // Get the underlying DOM scroll node from the RN web ScrollView + if (ref) { + const scrollable = ref as unknown as { + getScrollableNode?: () => HTMLElement + } + scrollNodeRef.current = + scrollable.getScrollableNode?.() ?? (ref as unknown as HTMLElement) + } + } + return ( {containerWidth > 0 && ( { + if (hasDragged.current) return ax.metric('post:gallery:openLightbox', { imageIndex: index, totalImages: images.length,