Skip to content

fix(google-maps): guard pan-on-open for closed/unpositioned overlay#698

Merged
harlan-zw merged 1 commit intomainfrom
fix/google-maps-overlay-pan-on-open-guard
Apr 9, 2026
Merged

fix(google-maps): guard pan-on-open for closed/unpositioned overlay#698
harlan-zw merged 1 commit intomainfrom
fix/google-maps-overlay-pan-on-open-guard

Conversation

@harlan-zw
Copy link
Copy Markdown
Collaborator

🔗 Linked issue

Follow-up to #697 (CodeRabbit nit, deferred during PR E review).

❓ Type of change

  • 📖 Documentation
  • 🐞 Bug fix
  • 👌 Enhancement
  • ✨ New feature
  • 🧹 Chore
  • ⚠️ Breaking change

📚 Description

<ScriptGoogleMapsOverlayView> previously scheduled panMapToFitOverlay from onAdd() whenever panOnOpen was enabled, even when the overlay started closed or draw() had not yet resolved a position. That caused unexpected map panning on initial mount/remount whenever the overlay was hidden.

This is a pre-existing bug surfaced by CodeRabbit during the PR E review. I deferred the fix from PR E to keep that PR focused on the class extraction + reactive position rendering refactor; this PR addresses it in isolation with its own regression test.

🛠 Fix

Two guards on the pan-on-open path in onAdd():

  1. Before scheduling the requestAnimationFrame, check open !== false. This skips the rAF entirely when the overlay is mounted closed.
  2. Inside the rAF callback, re-check open, overlayAnchor.value, and overlayPosition.value. State may have shifted during the frame: the controlled open could have flipped to false, the position may still be unresolved, or the component may have unmounted.
if (panOnOpen && open.value !== false) {
  const padding = typeof panOnOpen === 'number' ? panOnOpen : 40
  requestAnimationFrame(() => {
    if (open.value !== false && overlayAnchor.value && overlayPosition.value)
      panMapToFitOverlay(overlayAnchor.value, map, padding)
  })
}

🧪 Tests

Four new regression tests in test/nuxt-runtime/google-maps-overlay-view.nuxt.test.ts (panOnOpen guard for closed/unpositioned overlays describe block) that spy on requestAnimationFrame and assert against mockMap.panBy:

  • defaultOpen=false → no rAF scheduled, panBy not called
  • :open=false (controlled) → no rAF scheduled, panBy not called
  • panOnOpen=false → no rAF scheduled regardless of open state
  • happy path (open + positioned) → rAF still scheduled (guard does not over-block)

All 104 google-maps-* tests pass; lint and typecheck clean.

`<ScriptGoogleMapsOverlayView>` previously scheduled
`panMapToFitOverlay` from `onAdd()` whenever `panOnOpen` was enabled,
even when the overlay started closed or `draw()` had not yet resolved
a position. That caused unexpected map panning on initial mount and
remount when the overlay was hidden.

Add two guards:

1. Before scheduling the rAF, check `open !== false`. This skips the
   rAF entirely when the overlay is mounted closed.
2. Inside the rAF callback, re-check `open` and `overlayPosition` (and
   the anchor element). The state may have changed during the frame:
   the controlled `open` could flip to false, the position may not
   have resolved, or the component may have unmounted.

Tests cover the four pan-on-open paths:

- defaultOpen=false → no rAF scheduled
- :open=false (controlled) → no rAF scheduled
- panOnOpen=false → no rAF scheduled
- happy path (open + positioned) → rAF still scheduled
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Apr 9, 2026

Open in StackBlitz

npm i https://pkg.pr.new/@nuxt/scripts@698

commit: 9918a86

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 9, 2026

📝 Walkthrough

Walkthrough

The changes refine the panOnOpen behavior in the GoogleMaps overlay component by adding defensive guards to the pan operation. The production code now checks whether the overlay is open and whether valid positioning data exists before executing the pan during the animation frame. The test suite adds comprehensive coverage for these guard conditions across multiple scenarios including closed overlays, controlled open states, and disabled panOnOpen settings.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~15 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'fix(google-maps): guard pan-on-open for closed/unpositioned overlay' accurately and concisely summarizes the main change: adding guards to prevent unintended pan behavior when overlay is closed or unpositioned.
Description check ✅ Passed The PR description is well-detailed and directly related to the changeset, explaining the bug, the fix with code examples, and regression tests added.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/google-maps-overlay-pan-on-open-guard

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Apr 9, 2026

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

Project Deployment Actions Updated (UTC)
scripts-playground Ready Ready Preview, Comment Apr 9, 2026 3:16pm

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
test/nuxt-runtime/google-maps-overlay-view.nuxt.test.ts (1)

351-408: Consider adding one test that executes the queued rAF callback.

These tests cover scheduling well, but they don’t directly validate the in-callback guard. A focused case that captures the callback, flips open to false, then invokes the callback and asserts mockMap.panBy is not called would lock in the regression fix more tightly.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/nuxt-runtime/google-maps-overlay-view.nuxt.test.ts` around lines 351 -
408, Add a test that captures the queued requestAnimationFrame callback from the
existing rafSpy, mounts the overlay via mountOverlay (with position set and
panOnOpen default/true), then programmatically set the overlay's open prop to
false (or mount with controlled open and update it) before invoking the captured
rAF callback, and finally assert mocks.mockMap.panBy was not called; this will
exercise the in-callback guard inside the overlay's onAdd/panMapToFitOverlay
logic and lock in the regression fix.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMapsOverlayView.vue`:
- Around line 237-244: The guard currently treats panOnOpen falsy values (like
0) as disabled; update the conditional around panOnOpen in the block that
schedules requestAnimationFrame (the if checking panOnOpen && open.value !==
false) to explicitly check for non-null/undefined or boolean true—e.g. test
panOnOpen !== false && panOnOpen != null (or typeof panOnOpen === 'number' ||
panOnOpen === true) so numeric 0 is accepted; keep the rest of the logic
(calculating padding, calling draw(), and the requestAnimationFrame callback)
unchanged.

---

Nitpick comments:
In `@test/nuxt-runtime/google-maps-overlay-view.nuxt.test.ts`:
- Around line 351-408: Add a test that captures the queued requestAnimationFrame
callback from the existing rafSpy, mounts the overlay via mountOverlay (with
position set and panOnOpen default/true), then programmatically set the
overlay's open prop to false (or mount with controlled open and update it)
before invoking the captured rAF callback, and finally assert
mocks.mockMap.panBy was not called; this will exercise the in-callback guard
inside the overlay's onAdd/panMapToFitOverlay logic and lock in the regression
fix.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e9dfed62-71af-4078-940f-9c14faa6b9cd

📥 Commits

Reviewing files that changed from the base of the PR and between c33473c and 9918a86.

📒 Files selected for processing (2)
  • packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMapsOverlayView.vue
  • test/nuxt-runtime/google-maps-overlay-view.nuxt.test.ts

Comment on lines +237 to 244
if (panOnOpen && open.value !== false) {
// Wait for draw() to position the element, then pan. Re-check inside
// the rAF callback so we don't pan when:
// - the controlled `open` prop flipped to false during the frame
// - draw() never resolved a position (closed/missing position)
// - the anchor element is gone (component unmounted mid-frame)
const padding = typeof panOnOpen === 'number' ? panOnOpen : 40
requestAnimationFrame(() => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

panOnOpen: 0 is currently treated as disabled.

Line 237 uses a truthy guard (if (panOnOpen && ...)), so panOnOpen={0} won’t schedule panning even though numeric values are documented as valid custom padding. Please switch to an explicit boolean check.

Suggested fix
-      if (panOnOpen && open.value !== false) {
+      if (panOnOpen !== false && open.value !== false) {
         // Wait for draw() to position the element, then pan. Re-check inside
         // the rAF callback so we don't pan when:
         //   - the controlled `open` prop flipped to false during the frame
         //   - draw() never resolved a position (closed/missing position)
         //   - the anchor element is gone (component unmounted mid-frame)
         const padding = typeof panOnOpen === 'number' ? panOnOpen : 40
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (panOnOpen && open.value !== false) {
// Wait for draw() to position the element, then pan. Re-check inside
// the rAF callback so we don't pan when:
// - the controlled `open` prop flipped to false during the frame
// - draw() never resolved a position (closed/missing position)
// - the anchor element is gone (component unmounted mid-frame)
const padding = typeof panOnOpen === 'number' ? panOnOpen : 40
requestAnimationFrame(() => {
if (panOnOpen !== false && open.value !== false) {
// Wait for draw() to position the element, then pan. Re-check inside
// the rAF callback so we don't pan when:
// - the controlled `open` prop flipped to false during the frame
// - draw() never resolved a position (closed/missing position)
// - the anchor element is gone (component unmounted mid-frame)
const padding = typeof panOnOpen === 'number' ? panOnOpen : 40
requestAnimationFrame(() => {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/script/src/runtime/components/GoogleMaps/ScriptGoogleMapsOverlayView.vue`
around lines 237 - 244, The guard currently treats panOnOpen falsy values (like
0) as disabled; update the conditional around panOnOpen in the block that
schedules requestAnimationFrame (the if checking panOnOpen && open.value !==
false) to explicitly check for non-null/undefined or boolean true—e.g. test
panOnOpen !== false && panOnOpen != null (or typeof panOnOpen === 'number' ||
panOnOpen === true) so numeric 0 is accepted; keep the rest of the logic
(calculating padding, calling draw(), and the requestAnimationFrame callback)
unchanged.

@harlan-zw harlan-zw merged commit 506dfd8 into main Apr 9, 2026
17 checks passed
@harlan-zw harlan-zw deleted the fix/google-maps-overlay-pan-on-open-guard branch April 9, 2026 15:23
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