Skip to content

Make the two magnification surfaces offer the same affordances (double-tap on Lightbox, zoom buttons/keys in DiagramLightbox) #6135

Description

@CrysisDeu

Problem

The dashboard has exactly two full-viewport surfaces that own their own magnification, and after #6117 they still offer different ways to reach it:

pinch double-tap buttons keys
Lightbox (image viewer) yes no − / reset / + + / -
DiagramLightbox (mermaid viewer) yes yes no no

Both gaps were raised by the UX lane on #6117 and dispositioned there — the doc claim that implied the image viewer had a double-tap was corrected to describe shipped behaviour, and these two remain.

Why it matters

  • A user who learns the double-tap on a diagram tries it on an image and gets nothing. Nothing is broken, but the gesture vocabulary is inconsistent across two surfaces that look and behave alike.

  • In the diagram viewer, every desktop input has no working way to magnify — mouse, keyboard, and trackpad alike. Measured, because two earlier framings of this issue were wrong:

    • No controls exist. DiagramLightbox renders exactly one <button> (the close X, ~line 220) and its only key handler is Escape. The − / reset / + cluster and the +/-/0 bindings are the image viewer's (MarkdownRenderer.tsx:3237-3238, 3406-3412, 3496), not this one's.
    • Trackpad pinch does not reach the hook. A trackpad pinch produces no touch pointers: Blink reports it as ctrl+wheel, WebKit as gesturestart/gesturechange. DiagramLightbox monitors neither (grep -nE "onWheel|ctrlKey|gesturestart" → no matches) and usePinchZoom returns early on pointerType === 'mouse'. So "trackpad works, only mouse is unsupported" is not the situation.
    • Page zoom is not a fallback, which corrects what this issue said when filed. Page zoom was never disabled on desktop (fix(dashboard): stop the mobile shell page-zooming on a pinch #6000's suppression installs only under (pointer: coarse) and hooks only gesturestart/gesturechange/gestureend/touchmove; the viewport meta governs the touch visual viewport) — but it cannot magnify fit-to-viewport content. At 200% the viewport's CSS-pixel width halves, the fixed inset-0 box halves with it, and the SVG re-fits to that smaller box while each CSS pixel now covers 2 device pixels. The two cancel exactly: the labels come out the same apparent size.

    Net: the viewer opens at the state where its labels are smallest and a desktop user has no way out of it. The UX lane raised this on three heads of #6117; the third framing is the one that holds.

    Buttons plus keys cover all three inputs in one change — a control is input-agnostic, so it answers mouse, keyboard and trackpad together. Handling ctrl+wheel and gesturestart separately would be a second code path for the trackpad alone; only add it if a pinch specifically is wanted after the controls exist.

Neither is a regression — desktop was never able to magnify a fit-scaled diagram, before #6000 or after — but the second is a genuine dead end rather than a rough edge, and calling it merely "coarse" was wrong. The maintainer has ruled that this work lands here rather than in #6117, which ships with the touch path only; that PR carries the ruling and the measurements above.

Task

  1. Double-tap on Lightbox. usePinchZoom already carries the tap arithmetic used by DiagramLightbox, so the zoom half is small. The design step is the conflict: Lightbox owns one-finger swipe-dismiss, and a double-tap is two one-finger contacts in quick succession. Decide how a second tap is distinguished from the start of a swipe before wiring it, and keep MarkdownRenderer.lightboxSwipe.test.tsx (20 specs, 6 of them pinch) green — that suite is the contract for the existing gesture.
  2. Zoom buttons + keys in DiagramLightbox. Reuse the image viewer's − / reset / + cluster and +/- bindings, driving the same setZoom the hook returns. Note DiagramLightbox renders through createPortal (Lightbox does not), so tests query document.body, not the render container.

Worth doing together: both are "make the two magnification surfaces offer the same affordances", and doing one alone leaves the table above asymmetric in the other direction.

Notes

  • usePinchZoom's helpers are module-private on purpose and its returned surface is exactly what the two consumers destructure. If this work needs another field, add it back deliberately rather than re-exporting the internals.
  • The hook does not own one-finger gestures — that seam is why Lightbox keeps swipe-dismiss and DiagramLightbox keeps drag-pan in their own components. Item 1 should respect it rather than folding swipe thresholds into the hook.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: dashboardDashboard UI and its backend handlersbugSomething is not workingneeds-investigationTriage: requires deep analysis before a fix

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions