Fix drag constraints getting stuck when clicked during animation#3456
Fix drag constraints getting stuck when clicked during animation#3456mattgperry merged 3 commits intomainfrom
Conversation
When a draggable element with ref-based constraints is dragged outside its boundaries (with dragElastic), it should animate back within the constraints when released. However, if the user clicks on the element while it's animating back, the animation was being stopped and the element would get "stuck" outside the constraints. The fix: 1. Always pause (not stop) animations when pointerdown occurs, so the animation can be resumed if no drag starts 2. Resume the paused animation when the user releases without dragging (just clicking), ensuring the constraint animation continues Fixes #2697 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
Code ReviewI've reviewed PR #3456 which fixes the drag constraints bug where elements get stuck when clicked during constraint return animations. Overall, this is a well-implemented fix with excellent test coverage. Here's my detailed feedback: ✅ Strengths1. Root Cause Analysis & Fix
2. Excellent Test Coverage
3. Code Quality
🔍 Observations & Questions1. Simplified Logic in VisualElementDragControls (Lines 111-114) // Before: Conditional logic based on dragSnapToOrigin
dragSnapToOrigin ? this.pauseAnimation() : this.stopAnimation()
// After: Always pause
this.pauseAnimation()This simplification is good, but I'm curious about the implications:
2. Resume Condition in PanSession (Lines 183-187) if (this.dragSnapToOrigin || !this.startEvent) {
resumeAnimation && resumeAnimation()
}The
3. Test Precision expect(right).to.be.at.most(302) // 300 + 2px tolerance
expect(left).to.be.at.least(-2) // 0 - 2px toleranceThis is good defensive testing accounting for sub-pixel rendering and timing variations. 🎯 Suggestions1. Edge Case Testing
2. Performance Consideration
3. Documentation
🔒 Security & Performance
📝 Minor Nits
✅ Final VerdictLGTM with minor suggestions! This is a solid fix that:
The fix is minimal, well-tested, and addresses the reported issue (#2697) effectively. The 23 passing drag tests mentioned in the PR description give confidence this doesn't break existing functionality. Recommendation: Approve and merge after considering the questions about potential behavior changes in other drag scenarios (likely already verified by existing tests passing). Great work! 🎉 |
When snapToCursor is used, we need to STOP the animation (not pause) because snapToCursor sets new position values. A paused animation's state would interfere with the new values being set. The pause behavior is still needed for the constraint animation fix when snapToCursor is not used. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
PR Review: Fix drag constraints getting stuck when clicked during animationSummaryThis PR fixes a bug where draggable elements with ref-based constraints would get stuck outside boundaries when clicked during the constraint animation. The fix is well-implemented with good test coverage. Code Quality & Best Practices ✅Strengths:
Minor observations:
Logic & Implementation ✅VisualElementDragControls.ts changes (lines 111-121):
This is a good improvement over the previous PanSession.ts changes (lines 183-187):
This ensures constraint animations continue when interrupted by a click. Test Coverage ✅Excellent test coverage:
Test implementation notes:
Suggestions:
Performance Considerations ✅No performance concerns:
Security Concerns ✅No security issues identified. The changes:
Potential Issues & Edge CasesMinor consideration: Edge case to verify manually:
Suggestions
Overall AssessmentVerdict: Approved ✅ This is a well-crafted bug fix that:
The fix is elegant: by pausing instead of stopping animations, and resuming them when a click (not drag) occurs, constraint animations can properly continue after being interrupted. Great work! |
When dragging an element during a constraint animation (interrupting the animation with a new drag), the element would jump to the wrong position on release. The jump size was proportional to the second drag gesture size. Root cause: When a drag started during a paused animation, the motion value's get() returned stale data from the paused animation state instead of the current rendered position. This caused originPoint to be set incorrectly. Fix: Call stopAnimation() in onStart (when actual drag begins) to properly sync the motion value to its current position before recording originPoint. The animation lifecycle is now: 1. onSessionStart: pauseAnimation() - allows resume if no drag starts (click) 2. onStart (if drag begins): stopAnimation() - sync value for accurate originPoint 3. During drag: values set directly via set() 4. onEnd: startAnimation() - new constraint animation from correct position 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
Code ReviewI've reviewed PR #3456 and overall this is a well-crafted fix for a tricky edge case. The solution is elegant and the test coverage is excellent. Below are my findings: ✅ Strengths1. Clear Problem Understanding 2. Excellent Test Coverage
The third test is particularly good at catching regressions with its 200px drag movement verification. 3. Minimal, Surgical Changes 🔍 Code Quality ObservationsVisualElementDragControls.ts (lines 111-126)
PanSession.ts (lines 183-187)
💡 Potential Considerations1. Animation State Management Question: Is there any scenario where
Recommendation: Consider adding cleanup in cancel() {
this.isDragging = false
// ... existing code ...
this.stopAnimation() // Ensure any paused animations are cleaned up
// ... rest of code ...
}2. Memory/Performance 3. Test Timing
🔒 Security & PerformanceSecurity: ✅ No concerns. Changes are internal logic only, no user input handling modified. Performance: ✅ Minimal impact:
📝 Minor Suggestions1. Code Documentation // Animation state flow:
// 1. pointerdown → pause (preserves state for resume)
// 2. drag starts → stop (motion values need to reflect current position)
// 3. pointerup without drag → resume (continue constraint animation)2. Test File Naming 3. Type Safety ✅ Final VerdictThis PR successfully fixes issue #2697 with:
Recommendation: Approve with minor suggestion to add cleanup in The only substantive suggestion is ensuring paused animations are cleaned up in edge cases (component unmount, presence exit). Otherwise, this is production-ready. Great work on this fix! The state machine approach (pause → potentially resume) is much cleaner than the previous behavior. |
Summary
Fixes #2697
Closes #3394
Test plan
drag-constraints-return.tsxthat verifies:🤖 Generated with Claude Code