fix(detail): portal fullscreen viewer to body so modal zoom isn't blank#531
Closed
Zheaoli wants to merge 1 commit into
Closed
fix(detail): portal fullscreen viewer to body so modal zoom isn't blank#531Zheaoli wants to merge 1 commit into
Zheaoli wants to merge 1 commit into
Conversation
… blank Opening a photo's fullscreen zoom from the intercepted-route modal (grid → detail) showed a blank screen, while the same photo opened via a direct /preview/<id> link worked. Root cause: the fullscreen overlay uses `position: fixed; inset: 0`, but in the modal it is a descendant of Radix `DialogContent`, whose `translate-x-[-50%] translate-y-[-50%]` (+ zoom-in) transform establishes a containing block for fixed-positioned descendants. So the viewer was positioned relative to the dialog box instead of the viewport and never covered the screen → blank. The full-page route has no such transformed ancestor, which is why it worked. Render the overlay through `createPortal(..., document.body)` so its `fixed` positioning is always relative to the viewport, regardless of any transformed ancestor. Guarded with `typeof document !== 'undefined'` for SSR. The overlay stays in the React tree (portals preserve it), so the keep-mounted lifecycle and WebGL viewer teardown from the LRU work are unchanged. The dialog already prevents interact-outside dismissal (`onInteractOutside` preventDefault in the modal wrapper), so viewer gestures don't close it; viewer `z-[100]` stays above the dialog `z-50`. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Collaborator
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Symptom
Opening a photo's fullscreen zoom from the intercepted-route modal (album grid → detail) shows a blank screen. The same photo opened via a direct
/preview/<id>link works fine.Root cause
The fullscreen overlay (
components/album/progressive-image.tsx) usesposition: fixed; inset: 0. In the modal, it is a descendant of RadixDialogContent, whose class includestranslate-x-[-50%] translate-y-[-50%](plus azoom-in-95open animation). A transformed ancestor establishes the containing block forposition: fixeddescendants, so the viewer was positioned relative to the dialog box rather than the viewport → it never covered the screen → blank.The full-page
/preview/<id>route has no transformed ancestor, which is exactly why that path worked.(GPU-independent — the viewer mounts; it's just mispositioned/clipped. The earlier "View fullscreen toolbar button" mount-gate fix, #528, is a separate issue on a different path.)
Fix
Render the overlay through
createPortal(..., document.body)so itsfixedpositioning is always relative to the viewport, independent of any transformed ancestor. Guarded withtypeof document !== 'undefined'for SSR.onInteractOutside→preventDefault), so portaling the viewer out ofDialogContentdoesn't let zoom gestures close the dialog.z-[100]keeps the viewer above the dialogz-50(both at body level after portal).Verify
After deploy: album grid → open a photo (modal) → click the photo / "View fullscreen" → the zoomable image should now fill the viewport (previously blank). Direct
/preview/<id>should remain unaffected. Devtools: the overlay'sboundingClientRectshould be0,0,vw,vh, not trapped in the dialog box.(Headless note: the intercepted-route modal can't be reproduced in headless — synthetic clicks fall through to the full-page route — so the modal-path verification needs a real browser / Manjusaka.)