-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Refactor #3471
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
Refactor #3471
Conversation
Introduces a new `animateLayout` function that enables FLIP-style layout animations without React. Key features: - Automatic before/after snapshot detection - Enter/exit animations with `.enter()` and `.exit()` builder methods - Shared element transitions via `data-layout-id` attribute - Crossfade support for elements with matching layout IDs - Scale correction for border-radius and box-shadow Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
PR Review: Layout Animation System RefactorOverviewThis PR introduces a new layout animation system to motion-dom through the unstable_animateLayout API. The implementation adds ~1700 lines of code across 4 new modules plus comprehensive E2E test coverage. StrengthsArchitecture & Design
Code Quality
Issues & Concerns1. Potential Race Condition in Builder ExecutionLocation: LayoutAnimationBuilder.ts:50 The builder executes on a microtask via queueMicrotask(). Builder methods like .enter(), .exit(), and .shared() must be called synchronously, but this isn't enforced or documented. Risk: If a user adds await before chaining methods, execution will have already started and config will be ignored. Recommendation: Add guard in builder methods to throw if this.executed === true, and document this requirement. 2. Missing Null Safety in Parent Check (BLOCKING)Location: LayoutAnimationBuilder.ts:220 parentElement is typed as HTMLElement but could be null. Fix: Use optional chaining: 3. Non-Null Assertion Without Guard (BLOCKING)Location: projection-tree.ts:186 root! could be undefined if buildProjectionTree is called with empty array and no existingContext. Fix: Add guard or throw meaningful error before returning. 4. Type ConfusionLocation: LayoutAnimationBuilder.ts:342 The ternary 5. Opacity Manipulation Bypasses Motion ValuesLocation: LayoutAnimationBuilder.ts:274 Directly setting style.opacity bypasses Motion internal state management. Recommendation: Use visualElement.setStaticValue("opacity", 0) 6. Potential Memory Leak with Exit Elements (BLOCKING)Location: LayoutAnimationBuilder.ts:129 If groupAnimation.finished never resolves, exit elements remain in DOM forever. Fix: Handle both resolution and rejection: 7. Missing Return Type AnnotationLocation: can-animate.ts:7-13 Per CLAUDE.md, functions should have explicit return types. hasKeyframesChanged returns boolean | undefined. 8. Scale Corrector Global StateLocation: projection-tree.ts:14-36 Module-level singleton could cause issues in test isolation, SSR, and multi-instance scenarios. Performance ConsiderationsPositive:
Concerns:
Security✅ No security issues identified Test CoverageExcellent E2E coverage but missing unit tests for core logic (mutation detection, tree building, etc.). Per CLAUDE.md: "Always write a failing test FIRST before implementing any bug fix or feature." Recommendation: Add Jest unit tests for detectMutations, buildProjectionTree, etc. Minor Suggestions
VerdictOverall: Well-architected, production-quality implementation with excellent E2E coverage. Blocking Issues: #2, #3, #6 should be fixed before merge Recommendation: ✅ Approve with requested changes Great work on this complex feature! The projection system integration is particularly well done. 🚀 |
Pull Request Review: Layout Animation RefactorSummaryThis PR introduces a comprehensive layout animation system ( ✅ Strengths1. Excellent Architecture & Design
2. Robust Implementation
3. Comprehensive Test Coverage
4. Code Quality
🔍 Issues & ConcernsCritical Issues1. Missing Return Statement in
|
Refactored animateLayout to leverage the projection system's existing snapshot mechanism rather than using raw getBoundingClientRect. This eliminates duplicate measurements and ensures proper transform-aware measurements via willUpdate(). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Pull Request Review: Refactor - Layout Animation SystemI've completed a comprehensive review of this refactored layout animation system. Overall, this is excellent work with a well-architected solution. Here's my detailed feedback: ✅ Strengths1. Architecture & Design
2. Code Quality
3. Test Coverage
🔍 Potential Issues & Recommendations1. Critical: Non-null Assertion Operator (projection-tree.ts:186)root: root\!, // Line 186Issue: This assumes Recommendation: Add validation: if (\!root) {
throw new Error('Failed to create projection tree: no root node found')
}
return { nodes, visualElements, group, root }2. Performance: Microtask Queue Timing (LayoutAnimationBuilder.ts:51)queueMicrotask(() => this.execute())Issue: Using Recommendation: Consider documenting this behavior clearly, or add a flag to track if builder methods were called before execution. 3. Type Safety: Force Non-null in shared() (LayoutAnimationBuilder.ts:71)this.sharedTransitions.set(layoutIdOrOptions, options\!)Issue: The Recommendation: Add runtime validation: if (typeof layoutIdOrOptions === 'string') {
if (\!options) {
throw new Error('Options required when specifying layoutId')
}
this.sharedTransitions.set(layoutIdOrOptions, options)
}4. Magic Number: Viewport Box Threshold (script-assert.js:19)matchViewportBox: (element, expected, threshold = 0.01) => {Issue: Default threshold of 0.01px is extremely strict and may cause flaky tests due to sub-pixel rendering differences across browsers. Recommendation: Increase to at least 0.5-1px or make it configurable per-test. 5. Potential Memory Leak: Animation Cleanup (LayoutAnimationBuilder.ts:174-178)for (const [element, node] of context.nodes.entries()) {
if (sharedExitingElements.has(element)) continue
if (node.currentAnimation) {
animations.push(node.currentAnimation)
}
}Issue: If an animation is cancelled/interrupted before Recommendation: Add cleanup to all animation control methods (pause, cancel, stop) or use 6. Redundant Code: parseAnimateLayoutArgs (LayoutAnimationBuilder.ts:356)const scope = elements[0] || document
return {
scope: scope instanceof Document ? scope : scope, // Redundant ternary
...
}Issue: The ternary operator returns Recommendation: Simplify to: return {
scope: elements[0] || document,
...
}7. Edge Case: Opacity Initialization (LayoutAnimationBuilder.ts:287-289)if (targetOpacity === 1) {
;(element as HTMLElement).style.opacity = '0'
}Issue: This mutates the DOM element's style directly but doesn't restore it if the animation is cancelled. Also, the leading semicolon is unconventional. Recommendation:
8. Missing Validation: Element Connection Check (detect-mutations.ts:226)In Recommendation: Add validation that element isn't already connected elsewhere before reattaching. 🔒 Security Considerations✅ No security concerns identified. The code:
⚡ Performance ConsiderationsPositive:
Potential Improvements:
📝 Code Style & Best Practices✅ Excellent adherence to CLAUDE.md conventions:
Minor suggestions:
🧪 Test Coverage AssessmentCoverage: Excellent (9 comprehensive test files) ✅ Well covered:
📚 Documentation SuggestionsThe API documentation in
🎯 SummaryOverall Assessment: ⭐⭐⭐⭐½ (4.5/5) This is a high-quality refactor with solid architecture, comprehensive tests, and good code practices. The main concerns are:
Recommendation: ✅ Approve with minor fixes The critical issues are fixable without major refactoring. I'd suggest addressing items #1, #2, and #3 from the recommendations above before merging. Great work on this refactor! The builder pattern API is intuitive and the projection system integration is well thought out. 🚀 |
No description provided.