-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Allow drag within rotated parents #3486
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
When a draggable element is inside a rotated parent container, the drag offset needs to be transformed from screen space to the element's local coordinate space. This fix: - Adds applyParentRotation() method that computes cumulative rotation from all ancestor motion elements in the projection path - Applies inverse 2D rotation to both drag offset and velocity - Uses minimal bundle impact: only Math.cos/sin, no new dependencies - Leverages existing projection node data (path, latestValues) Fixes #3320
Pull Request Review: Allow drag within rotated parentsGreat fix for issue #3320! The implementation correctly addresses the problem of drag direction being inverted when a parent container is rotated. Here's my detailed review: ✅ Strengths
🔍 Potential Issues & Improvements1. Missing
|
Tests ensure that drag constraints work correctly when the draggable element has a rotated parent: - Tests for right, left, top, bottom constraints at 180 degrees - Tests for all constraints at 90 degrees - Baseline test for constraints with no rotation
Pull Request Review: Allow drag within rotated parentsSummaryThis PR fixes a bug where draggable elements inside rotated parent containers would move in the wrong direction. The fix applies an inverse rotation transformation to both drag offsets and velocity to correctly map screen-space coordinates to the element's local coordinate space. Code Quality & Best Practices ✅Strengths:
Suggestions for Improvement:
Potential Bugs or Issues 🔍
Performance Considerations ⚡
Security Concerns 🔒No security concerns identified. The mathematical transformations are straightforward and don't involve user input processing that could lead to injection or overflow issues. Test Coverage 🧪Excellent test coverage! The PR includes:
Suggestions to strengthen tests:
Additional Observations
ConclusionThis is a solid, well-implemented fix for a real user pain point. The mathematical approach is correct, the code is clean and efficient, and the test coverage is comprehensive. The suggestions above are minor improvements that would make the implementation even more robust, but the PR is ready to merge as-is. Recommendation: ✅ Approve with minor suggestions for future enhancement Great work addressing this issue! |
Tests dragging behavior when the parent element has an infinite 0-360 degree linear rotation animation (10 second duration): - Basic drag works while parent is rotating - Drag continues to follow pointer during rotation - Constraints are respected during animated rotation
Pull Request Review: Allow drag within rotated parentsOverviewThis PR fixes a bug where dragging elements with rotated parent containers causes inverted or incorrect drag directions. The solution applies coordinate space transformation to account for parent rotation. Code Quality & Best Practices ✅Strengths:
Potential Issues & Suggestions 🔍1. Missing Support for
|
Constraints are applied in LOCAL coordinate space, not screen space. With 180° rotation, screen directions are inverted relative to local: - To test right constraint (limits local +X), drag LEFT in screen - To test bottom constraint (limits local +Y), drag UP in screen - To test left constraint (limits local -X), drag RIGHT in screen - To test top constraint (limits local -Y), drag DOWN in screen
PR Review: Allow drag within rotated parentsSummaryThis PR fixes a critical bug where draggable elements inside rotated parent containers would move in incorrect directions. The fix applies inverse rotation transformations to convert drag offsets from screen space to local coordinate space. ✅ Strengths1. Excellent Test Coverage
2. Clean Implementation
3. Good Architecture
🔍 Issues & ConcernsCritical: Missing 3D Rotation SupportSeverity: High - The implementation only handles 2D rotation ( Lines 355-358: // Accumulate 2D rotation (rotate or rotateZ)
if (latestValues.rotate && typeof latestValues.rotate === "number") {
totalRotation += latestValues.rotate
}Problems:
Example failure case: <motion.div style={{ rotateX: 45 }}> {/* This rotation is ignored! */}
<motion.div drag />
</motion.div>Recommendation:
Minor: Code Quality Issues1. Loop iteration style inconsistency (line 353): for (let i = 0; i < path.length; i++) {
const { latestValues } = path[i]Repository prefers functional iteration. Consider: path.forEach(({ latestValues }) => {
// ...
})2. Magic number (line 365): const radians = (totalRotation * Math.PI) / 180Consider extracting as a constant or utility function since it appears twice: const DEG_TO_RAD = Math.PI / 180
const radians = totalRotation * DEG_TO_RAD3. Type safety - The Minor: Test CompletenessMissing test cases:
DocumentationMissing inline documentation for:
🎯 RecommendationsMust Fix (Blocking):
Should Fix (Non-blocking):
Nice to Have:
🔒 SecurityNo security concerns identified. ⚡ PerformanceExcellent - minimal performance impact:
📊 Overall AssessmentScore: 7.5/10 This is a well-crafted fix for an important bug with excellent test coverage. The implementation is clean and efficient. However, the lack of 3D rotation handling is a significant gap that could lead to subtle bugs and user confusion. Once the 3D rotation concern is addressed (even just with a warning), this would be ready to merge. Great work on the comprehensive tests and clean implementation! 🎉 |
When a parent element is animating (e.g., rotating continuously), the transformation applied to the drag offset becomes stale. This change: - Stores the screen-space offset during drag - Adds a frame update loop that recalculates the local position each frame - Ensures the element stays under the cursor even as the parent rotates
Pull Request ReviewI've reviewed PR #3486 which fixes dragging behavior when the parent element is rotated. This is a well-implemented solution to issue #3320. Here's my detailed analysis: ✅ Strengths1. Excellent Test Coverage
2. Clean Mathematical Implementation
3. Performance Optimization
4. Good Architecture
🔍 Potential Issues & Suggestions1. Frame Loop Memory Leak Risk
|
Instead of continuously re-transforming a cumulative screen offset (which caused drift as rotation changed), now we: - Track the screen offset delta since last pointer move - Transform only the delta using current rotation - Apply the transformed delta to current position This prevents drift when the pointer is stationary because we only update position when the pointer actually moves. The element naturally rotates with its parent, which is the expected behavior.
Pull Request Review: Allow drag within rotated parentsSummaryThis PR addresses issue #3320 by fixing drag behavior when a draggable element is inside a rotated parent container. The implementation transforms drag offsets from screen space to local coordinate space using inverse rotation matrices. ✅ StrengthsImplementation Quality
Test Coverage
🔍 Code Quality ObservationsPositive
Areas for Consideration1. Unused Field (Minor)The lastParentRotation field is initialized (line 82, 199) but never read. Suggestion: Remove if not needed, or add comment explaining its future use. 2. Method Visibility (Architectural)updateAxis() method (lines 343-362) is now unused but remains private. Since the new applyDelta() method replaces it, consider removing it or documenting the relationship. 3. Edge Case: No Projection NodegetParentRotation() returns 0 if no projection node exists (line 396). This is safe but worth verifying against real scenarios. 🐛 Potential IssuesCritical: Transform Origin AssumptionThe rotation transformation assumes transformOrigin is at center (which is set in the test at line 32). However, rotation with non-center origins requires translation compensation. If a parent has transformOrigin: "top left" or any non-center origin, the transformation will be incorrect. Recommendation: Document this limitation if acceptable for v1, OR extend getParentRotation() to return both rotation and origin, then adjust the transform accordingly. Minor: Nested Rotations with Different OriginsWhen multiple ancestors have different transform origins AND rotations, the cumulative transformation becomes more complex. The current implementation sums rotations (line 403) which works for same-origin ancestors but may produce inaccuracies with varied origins. ⚡ Performance ConsiderationsPositive
Concern: Per-Frame Rotation CalculationgetParentRotation() traverses the full projection path on every pointermove event. For deeply nested hierarchies (10+ ancestors), this could add measurable overhead. Potential optimization: Cache parent rotation during drag session, invalidate only on layout changes. 🧪 Test CoverageExcellent Coverage
Suggested Additional Tests
🔒 SecurityNo security concerns identified. This is purely computational geometry. 📋 RecommendationsMust Address
Should Consider
Nice to Have
ConclusionThis is a high-quality PR that solves a real user pain point with clean, mathematical correctness. The delta-based approach shows thoughtful iteration. The main concern is the transform origin assumption, which should be validated against real-world usage patterns. Recommendation: Approve with minor revisions (address transform origin documentation/testing) Great work on the comprehensive test suite and clear implementation! 🎉 |
This restores the frame loop approach but fixes the constraint issue: - Store cumulative screen offset (where cursor is relative to drag start) - Each frame, transform this offset using CURRENT rotation - Set position directly (originPoint + transformedOffset) rather than accumulating This means: - Element stays under cursor as parent rotates (recalculated each frame) - Constraints work correctly because we track unconstrained target in screen space and apply constraints fresh each frame - No drift because position is set absolutely, not accumulated from deltas
Pull Request Review: Allow drag within rotated parentsOverviewThis PR addresses issue #3320, fixing drag behavior when a draggable element has a rotated parent. The implementation transforms drag offsets from screen space to local coordinate space and includes comprehensive E2E tests. Strengths1. Well-Architected Solution
2. Excellent Test Coverage
3. Frame Loop Implementation Code Quality Observations1. Performance Consideration: Frame Loop Overhead The frame loop runs on every frame during drag, even when the parent isn't animating. Each frame calls getParentRotation() which iterates through the projection path, performs trig calculations even when rotation hasn't changed, and calls updateAxis() and render() unnecessarily. Suggestion: Consider optimizing for the static case by caching the rotation value and only updating if changed, or detecting if parent has animated rotation before starting the frame loop. 2. Mathematical Correctness 3. Velocity Transformation Potential Issues1. Edge Case: Transform Origin 2. 3D Rotations Not Handled Recommendation: Add a comment documenting this limitation. 3. Multiple Nested Rotations Test CoverageExcellent coverage overall, but consider adding:
SecurityNo security issues identified. The code properly cleans up frame loops and uses safe mathematical operations. RecommendationsShould Consider (High Priority):
Nice to Have: Final VerdictApprove with minor recommendations. This is a solid fix that correctly solves the reported issue, has excellent test coverage, follows the codebase patterns, and introduces minimal bundle size impact. The frame loop performance concern is the main area for potential optimization, but not a blocker since it only affects active drag operations. Great work on the comprehensive testing and clean implementation! |
|
Closing as although it works well for static rotations I feel like a more comprehensive approach would take into rotate animations also and it's not quite there. |
When a draggable element is inside a rotated parent container, the drag offset needs to be transformed from screen space to the element's local coordinate space.
This fix:
Fixes #3320