Reanimated 4 (New Architecture, #10980) rewrote spring termination: with `overshootClamping`, which drawer-layout always passes, an animation now ends as soon as the position leaves the corridor between its start and its target. Reanimated 3 only treated crossing the target as overshoot. So on Reanimated 4 any release whose velocity opposes the direction the drawer settles in ends the spring on its first frame, and the drawer teleports instead of animating. Two easy ways in: an aborted drag under `swipeMinDistance`/`swipeMinVelocity`, where `nextOpen` keeps its current value while the finger was moving the other way, and dragging the already-open drawer past its edge before releasing. Refresh the patch against upstream `main`, which fixes this by zeroing velocity that opposes the spring direction, and take the two other changes to the same function while we are here: an early return when the drawer is already at the target, and `useLayoutEffect` for the `open` prop so the follow-up `toggleDrawer` call does not depend on the spring still running to be deduped. Regenerated with `pnpm patch` / `pnpm patch-commit`. Also adds the patch doc this one was missing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011DRYvgEawpfehopEibJXQB
3.4 KiB
react-native-drawer-layout@4.2.3.patch
Backport of the current upstream toggleDrawer from
react-native-drawer-layout.
None of it is released on the 4.x line (4.2.9 is latest and still lacks all of
it); upstream only ships it on the 5.0.0-alpha line, which needs Gesture
Handler 3 and therefore react-native 0.82+. The patch can be dropped when we
move to drawer-layout 5.x.
The patch has three parts. The first landed in #8952; the other two were added when the New Architecture switch (#10980) brought Reanimated 4 with it.
1. Deduplicate toggleDrawer calls (animatingTo)
toggleDrawer fires twice for a single swipe: once when the gesture ends, and
again from the effect that watches the open prop, because ending the gesture
calls onOpen/onClose which updates our shell state. The second call
restarts the spring from the current position with no velocity, which reads as
a stutter mid-animation.
animatingTo records which direction is in flight and the second call returns
early. Fixes the drawer jitter investigated in #8947 and #8949.
2. Ignore release velocity that opposes the spring direction
Reanimated 4 rewrote spring termination. With overshootClamping: true (which
this library always passes), the animation now ends as soon as the position
leaves the corridor between its start and its target:
const leftBound = startValue >= 0 ? toValue : toValue + startValue
const rightBound = leftBound + Math.abs(startValue)
if (current < leftBound || current > rightBound) {
return true // terminating
}
Reanimated 3 only treated crossing the target as overshoot, so a spring that first moved away from its target (which is what an initial velocity pointing the other way produces) was left to swing back on its own.
The consequence on Reanimated 4 is that any release whose velocity opposes the
direction the drawer settles in ends the spring on its first frame, so the
drawer teleports instead of animating. Both cases are easy to hit: an aborted
drag under swipeMinDistance/swipeMinVelocity, where nextOpen keeps its
current value while the finger was moving the other way, and dragging the
already-open drawer further past its edge before releasing.
Zeroing the opposing velocity keeps the animation inside the corridor. Real flings, whose velocity agrees with the target, are passed through untouched.
3. useLayoutEffect for the open prop
Upstream moved the effect that calls toggleDrawer(open) off useEffect, so
the follow-up call described in part 1 happens in the same commit rather than a
frame later. Part 1 dedupes it either way, but the dedupe window is only as
long as the spring runs, so not depending on that is worth the one-line change.
Notes
restDisplacementThreshold and restSpeedThreshold are left in the spring
config, but they are inert on Reanimated 4 - it settles on a relative
energyThreshold instead, and those two options survive only as no-op layout
animation builder methods. The drawer animation is roughly 200ms shorter than
it was on Reanimated 3 as a result. The spring itself is deliberately left at
this library's stiffness: 1000, damping: 500, mass: 3; upstream has since
retuned it to an underdamped 500/40/1, which would change how the drawer
feels and is a separate decision.