#71·mapcn

[Bug] Controlled viewport does not restore rejected movement

Author: km-git007Created Jul 17, 2026Updated Jul 17, 2026

Reproduction

typescript
const lockedViewport: MapViewport = {
  center: [2.3522, 48.8566],
  zoom: 10,
  bearing: 0,
  pitch: 0,
};

<Map
  viewport={lockedViewport}
  onViewportChange={() => {
    // Intentionally reject the proposed user movement.
  }}
/>
  1. Drag or zoom the map.
  2. Release the gesture.

Actual behavior

The map remains at the user-moved viewport even though the controlled prop never changed.

Expected behavior

The controlled fields return to the values in viewport after the gesture ends.

Cause

The prop-sync effect returns while map.isMoving() is true. Because the parent retained the same prop object/value, the effect has no dependency change after moveend, so it never reconciles the rejected movement.

Proposed compatibility contract

  • viewport + onViewportChange: fields present in viewport are authoritative.
  • onViewportChange alone: observer-only mode remains unchanged.
  • viewport alone: initial-value behavior remains unchanged.
  • Omitted fields remain independently uncontrolled.
  • Rejected movement reconciles on moveend.
  • A new conflicting authoritative prop during movement stops movement and applies immediately.

I can send a focused fix with no dependency or public prop additions. If this contract matches your intent, please assign the issue to km-git007 or comment exactly approved for implementation.