Skip to content

feat: add native overlay entering animations#26

Merged
piotr-graczyk-dev merged 3 commits into
mainfrom
codex/overlay-entering-animations
Jun 28, 2026
Merged

feat: add native overlay entering animations#26
piotr-graczyk-dev merged 3 commits into
mainfrom
codex/overlay-entering-animations

Conversation

@piotr-graczyk-dev

Copy link
Copy Markdown
Contributor

Summary

  • add public markerEnteringAnimation, clusterEnteringAnimation, and per-marker enteringAnimation APIs with native spec/type support
  • implement native fade/fade-scale entering animations for markers and clusters on iOS and Android
  • document the API, defaults, reduce-motion behavior, and architecture decision
  • update the example app to demonstrate default marker/cluster animations and marker opt-out

Validation

  • bun run typecheck
  • bun run typecheck:provider-types
  • bun run build
  • ./gradlew :app:compileDebugKotlin -PreactNativeArchitectures=arm64-v8a
  • iOS simulator runtime QA: Apple MapKit and Google Maps scenarios loaded with visible markers/clusters
  • Android runtime QA: Google tiles loaded, Scenario 5 clusters visible after viewport-size fix, Scenario 2 Landmarks markers visible, no Google Maps auth/crash logs

Runtime evidence

  • /private/tmp/nitro-ios-qa-apple-advanced.png
  • /private/tmp/nitro-ios-qa-google-advanced.png
  • /private/tmp/nitro-android-qa-scenario5-viewport-fix.png
  • /private/tmp/nitro-android-qa-scenario2-viewport-fix.png

@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2a7ca32f-c104-42e0-a78d-13afd200382f

📥 Commits

Reviewing files that changed from the base of the PR and between 33405d4 and ced77ca.

📒 Files selected for processing (10)
  • README.md
  • docs/architecture.md
  • example/App.tsx
  • package/ios/GoogleMapOverlayController.swift
  • package/ios/GoogleMapProviderAdapter.swift
  • package/ios/GoogleMapsAPIKey.swift
  • package/ios/HybridMapView.swift
  • package/ios/HybridMapViewDelegate.swift
  • package/ios/MapProviderAdapter.swift
  • package/ios/OverlayEnteringAnimation.swift
🚧 Files skipped from review as they are similar to previous changes (2)
  • package/ios/MapProviderAdapter.swift
  • example/App.tsx

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added configurable entering animations for map markers and marker clusters via markerEnteringAnimation / clusterEnteringAnimation.
    • Added per-marker overrides using MarkerDescriptor.enteringAnimation; use false to disable.
    • Documented presets, timing (duration/delay), reduce-motion behavior, and provider capability differences; added MarkerDescriptor and OverlayEnteringAnimation public types.
  • Bug Fixes
    • Improved entering-animation diffing/cancellation and state syncing; cluster enter handling now avoids unnecessary diff churn.
  • Documentation
    • Updated README, architecture/ADR, glossary, roadmap, and API typings; enhanced example UI to demonstrate the new option.
  • Tests
    • Extended type tests for supported/unsupported animation prop combinations.

Walkthrough

Adds marker and cluster entering-animation types, normalizes them into native descriptors, forwards them through map props and adapters, and executes them in iOS and Android overlay pipelines. The example app and documentation are updated to show the new behavior.

Changes

Overlay Entering Animations

Layer / File(s) Summary
Public types and native specs
package/src/types/overlays.ts, package/src/native/specs/overlays.ts, package/src/native/specs/MapView.nitro.ts, package/src/types/map.ts, package/src/types/index.ts, package/src/index.ts
Defines OverlayEnteringAnimation types, adds MarkerDescriptor.enteringAnimation, and extends MapViewProps plus exported type re-exports for marker and cluster animation props.
Normalization and MapView wiring
package/src/utils/enteringAnimation.ts, package/src/components/MapView.tsx, package/src/hooks/useCollectedOverlays.ts, package/type-tests/provider-props.ts
Normalizes public animation inputs into native descriptors, projects marker descriptors for markersProp, forwards normalized animation props to NativeMapView, and updates provider prop type tests.
iOS animation resolver
package/ios/OverlayEnteringAnimation.swift
Adds resolved entering-animation models and helpers for view and Google marker animations, including timing normalization and run gating.
iOS annotation models and cluster engine
package/ios/MapMarkerAnnotation.swift, package/ios/MapClusterAnnotation.swift, package/ios/MarkerClusterEngine.swift, package/ios/NitroPinAnnotationView.swift
Stores resolved entering animations on annotations, passes animation inputs through annotation creation, and toggles marker insertion animation based on system mode.
iOS overlay controllers and delegate
package/ios/MapOverlayController.swift, package/ios/HybridMapViewDelegate.swift, package/ios/GoogleMapOverlayController.swift
Wires animation descriptors into annotation creation and triggers per-annotation entering animations for MapKit and Google Maps overlays.
iOS adapter and HybridMapView wiring
package/ios/MapProviderAdapter.swift, package/ios/HybridMapView.swift, package/ios/AppleMapProviderAdapter.swift, package/ios/GoogleMapProviderAdapter.swift, package/ios/MarkerViewportFilter.swift
Adds animation properties to the provider contract and adapters, propagates them through HybridMapView, clears them on recycle, and includes animation state in marker fingerprinting.
Android animation resolver
package/android/src/main/java/com/margelo/nitro/nitromaps/OverlayEnteringAnimation.kt
Defines the Android resolved animation model and resolver logic for mapping descriptors, clamping timing values, and deciding when animations should run.
Android overlay animation pipeline
package/android/src/main/java/com/margelo/nitro/nitromaps/MapOverlayController.kt, package/android/src/main/java/com/margelo/nitro/nitromaps/MarkerClusterEngine.kt
MapOverlayController gains marker and cluster animation properties, resolves animations for added overlays, forces retained markers visible, and replaces the old fixed fade-in path; cluster diff identity is also changed.
Android adapter and HybridMapView wiring
package/android/src/main/java/com/margelo/nitro/nitromaps/MapProviderAdapter.kt, package/android/src/main/java/com/margelo/nitro/nitromaps/HybridMapView.kt, package/android/src/main/java/com/margelo/nitro/nitromaps/GoogleMapProviderAdapter.kt, package/android/src/main/java/com/margelo/nitro/nitromaps/MarkerViewportFilter.kt
Android provider contracts and HybridMapView gain animation properties and lifecycle plumbing, while the Google adapter forwards animation state and updates overlay viewport sizing through map lifecycle points.
Examples and documentation
example/App.tsx, example/examples/landmarks.ts, README.md, CONTEXT.md, docs/adr/0003-native-overlay-entering-animations.md, docs/architecture.md, docs/roadmap.md
The example app, fixtures, and written documentation describe and exercise marker and cluster entering animations.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 1.39% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise, correctly prefixed, and clearly matches the native overlay entering animation changes.
Description check ✅ Passed The description directly matches the PR’s scope, covering APIs, native animation behavior, docs, example updates, and validation.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@package/android/src/main/java/com/margelo/nitro/nitromaps/MapOverlayController.kt`:
- Line 245: The enter animation in MapOverlayController’s marker handling is not
being tracked, so stale animators can keep writing alpha on retained markers and
cause flicker. Update the marker enter-animation flow around the alpha reset and
the animator setup in the affected marker refresh paths so each created animator
is stored and canceled or replaced when a marker is retained. Use the existing
marker lifecycle methods in MapOverlayController to ensure old animations cannot
mutate the same marker after a refresh.
- Around line 267-319: The Android entering-animation path in animateEntering
currently only updates marker.alpha, so
ResolvedOverlayEnteringAnimationKind.FADE_SCALE is never actually applied and
behaves like a plain fade. Update the shared animator logic in animateEntering
to branch on the resolved animation kind from OverlayEnteringAnimationResolver
and apply the scale transform alongside alpha for FADE_SCALE, while keeping
revealAnimatedMarkers responsible for restoring the final marker state after
animation end/cancel.

In `@package/ios/GoogleMapOverlayController.swift`:
- Around line 188-191: The Google iOS overlay path in GoogleMapOverlayController
is resolving `.fadeScale`, but the downstream Google marker helper only applies
opacity, so the scale part is never used. Update the Google-backed animation
flow around `enteringAnimation(for:)`,
`OverlayEnteringAnimationResolver.prepareGoogleMarker`, and
`OverlayEnteringAnimationResolver.animateGoogleMarker` to also apply a scale
transform when the animation is `fadeScale`, while keeping `.fade` behavior
unchanged.
- Around line 211-223: The enteringAnimation path in GoogleMapOverlayController
should explicitly apply the native Google Maps appear animation when the
resolved animation is .system, since the Google helper returns early and
GMSMarker.appearAnimation otherwise stays .none. Update the marker and cluster
insertion flow around enteringAnimation/OverlayEnteringAnimationResolver so
that, before assigning marker.map = mapView, the marker’s native appear
animation is set appropriately for the .system case.

In `@package/ios/NitroPinAnnotationView.swift`:
- Around line 21-23: The reusable pin view is carrying over mutated visual state
from interrupted custom insert animations, so reset the view before applying a
new marker in NitroPinAnnotationView.configure(for:) (especially alpha and
transform, alongside any other transient animation state) and then reapply the
marker-specific animatesWhenAdded logic. Make the reset happen every time the
annotation view is configured/dequeued so a .system or .none marker cannot
inherit a transparent or scaled state from a prior fade/fade-scale insert.

In `@package/ios/OverlayEnteringAnimation.swift`:
- Around line 82-99: The Google marker path in prepareGoogleMarker and
animateGoogleMarker only changes marker.opacity, so .fadeScale is being treated
like a plain fade. Update the Google-backed animation branch in
OverlayEnteringAnimation to either apply a scale animation to an iconView/layer
when animation.kind is .fadeScale, or map .fadeScale to .fade before this path
so the behavior is consistent.
🪄 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: 66750d5e-ca57-4500-8aaa-9ec58d1b9da9

📥 Commits

Reviewing files that changed from the base of the PR and between 2fe93e3 and 248743a.

📒 Files selected for processing (37)
  • CONTEXT.md
  • README.md
  • docs/adr/0003-native-overlay-entering-animations.md
  • docs/architecture.md
  • docs/roadmap.md
  • example/App.tsx
  • example/examples/landmarks.ts
  • package/android/src/main/java/com/margelo/nitro/nitromaps/GoogleMapProviderAdapter.kt
  • package/android/src/main/java/com/margelo/nitro/nitromaps/HybridMapView.kt
  • package/android/src/main/java/com/margelo/nitro/nitromaps/MapOverlayController.kt
  • package/android/src/main/java/com/margelo/nitro/nitromaps/MapProviderAdapter.kt
  • package/android/src/main/java/com/margelo/nitro/nitromaps/MarkerClusterEngine.kt
  • package/android/src/main/java/com/margelo/nitro/nitromaps/MarkerViewportFilter.kt
  • package/android/src/main/java/com/margelo/nitro/nitromaps/OverlayEnteringAnimation.kt
  • package/ios/AppleMapProviderAdapter.swift
  • package/ios/GoogleMapOverlayController.swift
  • package/ios/GoogleMapProviderAdapter.swift
  • package/ios/HybridMapView.swift
  • package/ios/HybridMapViewDelegate.swift
  • package/ios/MapClusterAnnotation.swift
  • package/ios/MapMarkerAnnotation.swift
  • package/ios/MapOverlayController.swift
  • package/ios/MapProviderAdapter.swift
  • package/ios/MarkerClusterEngine.swift
  • package/ios/MarkerViewportFilter.swift
  • package/ios/NitroPinAnnotationView.swift
  • package/ios/OverlayEnteringAnimation.swift
  • package/src/components/MapView.tsx
  • package/src/hooks/useCollectedOverlays.ts
  • package/src/index.ts
  • package/src/native/specs/MapView.nitro.ts
  • package/src/native/specs/overlays.ts
  • package/src/types/index.ts
  • package/src/types/map.ts
  • package/src/types/overlays.ts
  • package/src/utils/enteringAnimation.ts
  • package/type-tests/provider-props.ts

Comment thread package/ios/GoogleMapOverlayController.swift Outdated
Comment thread package/ios/GoogleMapOverlayController.swift
Comment thread package/ios/NitroPinAnnotationView.swift
Comment thread package/ios/OverlayEnteringAnimation.swift Outdated
@piotr-graczyk-dev
piotr-graczyk-dev force-pushed the codex/overlay-entering-animations branch from 248743a to 4f3a51d Compare June 28, 2026 08:36

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@example/App.tsx`:
- Around line 337-361: ScalePressable currently does not forward accessibility
props, so the selected state in this animation option list is not exposed to
screen readers. Update the ScalePressable component to accept and pass through
accessibilityRole, accessibilityState, and accessibilityLabel to
AnimatedPressable, then use those props in the animation selector where
onSelectAnimation and ANIMATION_OPTIONS are rendered so the active option is
announced correctly.
- Around line 584-591: The demo initializes the animation picker to the wrong
default, so the UI starts on Scale instead of the documented API default. Update
the initial value used by App.tsx’s animation state in the App component so
animationOptionIndex points to system in ANIMATION_OPTIONS, keeping the picker
and displayed default in sync.
🪄 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: 6972e349-f401-4af1-8b8f-96736f882ee5

📥 Commits

Reviewing files that changed from the base of the PR and between 4f3a51d and 33405d4.

📒 Files selected for processing (1)
  • example/App.tsx

Comment thread example/App.tsx
Comment thread example/App.tsx Outdated
@piotr-graczyk-dev
piotr-graczyk-dev merged commit f056c1e into main Jun 28, 2026
3 checks passed
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