chat-ui
2ef6c831 - Add pinch-zoom and pan gestures to image lightbox (#2261)

Commit
7 days ago
Add pinch-zoom and pan gestures to image lightbox (#2261) * Add touch gestures to image lightbox Pinch-to-zoom, double-tap toggle, and pan when zoomed are essential on phones; without them iOS users couldn't zoom into chat images at all because the overlay disabled native pinch. - Pointer Events for unified touch/mouse/pen handling - Pinch (2 pointers) zooms about the midpoint with rubber-band overshoot - One-finger pan when zoomed, with rubber-band at the edges and hard-clamp on release - Double-tap on image toggles between 1x and 2.5x at the tap point - Trackpad pinch (Ctrl+wheel) and wheel pan on desktop - touch-action: none disables iOS native pinch / double-tap zoom - Tap-to-close preserved on overlay at scale 1; X button and Escape still close from any state * Harden image lightbox gestures against PhotoSwipe-style edge cases Audit against PhotoSwipe v5 and pinch-zoom-element surfaced three real bugs and several robustness gaps. Pinch math itself was already correct. Bugs: - Wheel deltaMode wasn't normalized; Firefox LINE-mode mouse wheels produced ~1% scale changes per tick instead of ~15%. - iOS Safari's proprietary gesturestart/gesturechange/gestureend can trigger native page-zoom on a fullscreen overlay even with touch-action:none; now blocked. - Body-only overflow lock leaves iOS rubber-band bounce on the page underneath; lock html overflow too. Robustness: - Cap active pointers at 2 to avoid stale pinch baselines on 3-finger touches (matches PhotoSwipe). - preventDefault on touch pointerdown for the image/overlay (not the close button) to suppress emulated mouse events. - Move pointermove/pointerup/pointercancel to window so mouse pans that exit the viewport keep tracking (matches PhotoSwipe / pinch-zoom). - captureBaseSize now temporarily clears the transform before measuring, so orientation changes while zoomed don't drift the bounds. - Tighten double-tap distance from 30px to 25px (PhotoSwipe parity). * Extract gesture logic to PinchZoomImage component ImageLightbox had grown to ~340 lines mixing portal/overlay/keyboard orchestration with pinch-zoom-pan gesture handling. Extract the gesture surface into a self-contained component. PinchZoomImage owns: pointer/wheel/iOS-gesture listeners, scale/tx/ty state, pinch math, double-tap, rubber-band, transform styling. It exposes a single onTapEmpty callback for "user tapped outside the image while not zoomed". ImageLightbox is now 56 lines: just the portal, overlay backdrop, close button, Escape key, and html/body scroll lock. Component (over action) was the right fit here: the gesture state needs to drive inline styles and class bindings on a specific surface+image DOM structure that we own. Actions are best for behavior layered onto foreign elements; here we own the markup. --------- Co-authored-by: Claude <noreply@anthropic.com>
Author
Parents
Loading