Skip to content

fix(files): zoom file viewer content, not the browser page#4741

Merged
waleedlatif1 merged 2 commits into
stagingfrom
waleedlatif1/file-viewer-zoom-fix
May 26, 2026
Merged

fix(files): zoom file viewer content, not the browser page#4741
waleedlatif1 merged 2 commits into
stagingfrom
waleedlatif1/file-viewer-zoom-fix

Conversation

@waleedlatif1
Copy link
Copy Markdown
Collaborator

Summary

  • Switch image, SVG, mermaid, and inline-markdown-image previews to a native non-passive wheel listener so trackpad pinch zooms the content instead of the browser page.
  • Accept metaKey alongside ctrlKey so Cmd+scroll on macOS zooms (matches Figma/tldraw/Excalidraw convention); this benefits all viewers using bindPreviewWheelZoom including PDF, DOCX, and PPTX.
  • Render SVG file previews via <img src={blobUrl}> (browser-enforced secure static mode) instead of a sandboxed iframe — same security posture, and pinch events now reach the zoom container instead of being trapped in the iframe.

Type of Change

  • Bug fix

Testing

Tested manually — trackpad pinch on images, SVG files, PDFs, DOCX, and PPTX now zooms the file content. Cmd+scroll on Mac also zooms. Two-finger pan and toolbar buttons work as before.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel
Copy link
Copy Markdown

vercel Bot commented May 26, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped May 26, 2026 7:14pm

Request Review

@cursor
Copy link
Copy Markdown

cursor Bot commented May 26, 2026

PR Summary

Low Risk
UI-only preview interaction and SVG display path changes; no auth, API, or data-layer impact.

Overview
Fixes file preview zoom so trackpad pinch and Cmd/Ctrl+scroll zoom the preview content instead of the browser page, by routing wheel handling through a non-passive native listener on the preview viewport.

bindPreviewWheelZoom now treats metaKey like ctrlKey for zoom (macOS Cmd+scroll), and supports an optional onPan callback that consumes two-finger scroll for transform-based viewers instead of relying on container scroll.

ZoomablePreview drops the React onWheel handler and wires zoom/pan through bindPreviewWheelZoom on the viewport ref.

SVG file previews switch from a sandboxed iframe + srcDoc to an <img> fed by a blob: URL (with revoke on cleanup), so pinch/wheel reaches the same zoom layer as other image previews while keeping static SVG display semantics.

Reviewed by Cursor Bugbot for commit d0f37e7. Configure here.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 26, 2026

Greptile Summary

This PR fixes trackpad pinch-to-zoom on the file viewer by replacing React's synthetic onWheel (passive by default, silently ignoring preventDefault) with a native non-passive listener via bindPreviewWheelZoom. It also adds metaKey support for Cmd+scroll on macOS and switches SVG previews from a sandboxed iframe to an <img> element backed by a properly lifecycle-managed blob URL.

  • preview-wheel-zoom.ts: Adds metaKey alongside ctrlKey for zoom detection and an onPan option that lets transform-based viewers intercept plain scroll events; listener is always registered non-passive so preventDefault() is honored.
  • zoomable-preview.tsx: Moves wheel handling from a React onWheel prop to a useEffect-bound native listener — the core fix that makes content zoom instead of browser zoom.
  • preview-panel.tsx: Replaces the SVG iframe with a blob-URL <img> using useState+useEffect for correct resource cleanup; security posture is equivalent since SVG loaded as an image cannot execute scripts or load external resources.

Confidence Score: 5/5

Safe to merge — the change is narrowly scoped to wheel-event handling and SVG rendering, with no impact on data, auth, or server-side logic.

All three files make targeted, well-reasoned changes. The move to a non-passive native listener directly fixes the reported bug. The blob-URL lifecycle is handled correctly using useState+useEffect. The only cosmetic issue is the brief broken-image frame from the initial empty src string.

preview-panel.tsx — the initial empty blobUrl state produces a brief broken-image placeholder; minor but worth addressing.

Important Files Changed

Filename Overview
apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/preview-wheel-zoom.ts Adds metaKey support alongside ctrlKey for pinch/zoom, introduces an optional onPan callback, and ensures the wheel listener is registered as non-passive so preventDefault() actually works — fixing the root cause of browser-level page zoom hijacking.
apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/zoomable-preview.tsx Replaces the React synthetic onWheel handler (passive by default, so preventDefault() was silently dropped) with a native listener via useEffect + bindPreviewWheelZoom. Dependency on stable applyZoom (empty useCallback dep array) means the listener is bound exactly once.
apps/sim/app/workspace/[workspaceId]/files/components/file-viewer/preview-panel.tsx Replaces the sandboxed SVG iframe with an img element backed by a blob URL managed via useState+useEffect (correct lifecycle pattern). Initial blobUrl='' causes a brief broken-image frame before the effect fires.

Sequence Diagram

sequenceDiagram
    participant User as User trackpad
    participant Browser
    participant Viewport as ZoomablePreview
    participant WheelZoom as bindPreviewWheelZoom
    participant ReactState as React state

    User->>Browser: pinch gesture
    Browser->>Viewport: WheelEvent with ctrlKey true
    Note over Viewport,WheelZoom: Non-passive native listener in capture phase
    Viewport->>WheelZoom: onWheel fires
    WheelZoom->>WheelZoom: preventDefault stops browser zoom
    WheelZoom->>ReactState: onZoom callback runs applyZoom
    ReactState->>Viewport: re-render with new zoom transform

    User->>Browser: two-finger pan
    Browser->>Viewport: WheelEvent no modifier key
    Viewport->>WheelZoom: onWheel fires
    WheelZoom->>WheelZoom: onPan present so preventDefault
    WheelZoom->>ReactState: onPan callback runs setOffset
    ReactState->>Viewport: re-render with new offset transform
Loading

Reviews (2): Last reviewed commit: "fix(files): use effect lifecycle for SVG..." | Re-trigger Greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit d0f37e7. Configure here.

@waleedlatif1 waleedlatif1 merged commit bc99c45 into staging May 26, 2026
14 checks passed
@waleedlatif1 waleedlatif1 deleted the waleedlatif1/file-viewer-zoom-fix branch May 26, 2026 19:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant