Repository navigation
feat: report CSS animation events from the engine - #10070
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
📝 WalkthroughSummary by CodeRabbit
WalkthroughCSS animations now parse event masks, calculate milestone elapsed times, report cancellations, and emit lifecycle events through the registry’s CSS event emitter. ChangesCSS animation event reporting
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant CSSAnimationsRegistry
participant CSSAnimation
participant CSSLoopAnimation
participant AnimationProgressProvider
participant CSSEventsEmitter
CSSAnimationsRegistry->>CSSAnimation: apply eventMask
CSSAnimation->>CSSLoopAnimation: register milestone reporter
CSSLoopAnimation->>AnimationProgressProvider: observe lifecycle milestone
AnimationProgressProvider->>CSSLoopAnimation: milestone and elapsed time
CSSLoopAnimation->>CSSAnimation: forward milestone
CSSAnimation->>CSSAnimationsRegistry: onAnimationEvent(metadata)
CSSAnimationsRegistry->>CSSEventsEmitter: emit CSS animation event
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
99d90e6 to
5a9d10a
Compare
35a39a9 to
c4c7ce0
Compare
c4c7ce0 to
9a490f0
Compare
9a490f0 to
4533be0
Compare
4533be0 to
f8629d4
Compare
f8629d4 to
5516178
Compare
087444c to
0b8a27f
Compare
caee059 to
81dbde5
Compare
2aed068 to
98c10bb
Compare
ed37fc9 to
4c0d6ed
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@packages/react-native-reanimated/Common/cpp/reanimated/CSS/progress/AnimationProgressProvider.h`:
- Line 84: Preserve the previously reached finite interval end when
CSSLoopAnimation::updateSettings() changes the iteration count to infinite, so
AnimationProgressProvider::intervalEnd() still reports that historical boundary
for the restarted animationstart event. Update the lifecycle timing state used
by RunLifecycle::reachPhase() rather than allowing the infinite configuration to
reset it to zero, and add a regression test covering a finished run followed by
setIterationCount(-1).
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: e72d105d-e0cb-4dd6-b273-f7739c91954d
📒 Files selected for processing (1)
packages/react-native-reanimated/Common/cpp/reanimated/CSS/progress/AnimationProgressProvider.h
`RunLifecycle` tracks which phase a run is in and reports the milestones each phase change crosses. It knows nothing about animations or transitions: the owner maps `Created`, `Started`, `Ended`, `Repeated` and `Aborted` to its own events. The phase changes come straight from the tables in [css-animations-2](https://drafts.csswg.org/css-animations-2/#event-dispatch) and [css-transitions-2](https://drafts.csswg.org/css-transitions-2/#event-dispatch), which agree on every row. That includes the rows that move a run backwards, which a style update reaches by re-timing a run that is already going or already finished. A milestone can be reached by more than one phase change, and the time it carries differs: a start is the interval start entering from a delay and the interval end re-entering after finishing. Hence `MilestoneTime`, used by the owners in #10070 and #10120. Pausing also moves out of the progress state, fixing an animation created with `playState: Paused` reporting `animationstart` while still paused and never once it actually started. Nothing registers a reporter yet. First step of the CSS animation callbacks series.
4c0d6ed to
0f26e5b
Compare
A start reports the interval start when the run enters from its delay and the interval end when it re-enters after finishing, so the milestone alone no longer identifies which time to send.
A run dropped back an iteration by re-timing crosses the end of the iteration it lands in, not the start.
A finished run that is given an infinite iteration count starts again, and the clamp turned its interval end into zero. The web reports the start with an infinite elapsed time there.
The transport for CSS events: a buffer that batches whatever is emitted and hands it to JS in one call, plus the JSI entrypoint that installs the receiving function. Nothing emits yet, so this is inert on its own. #10070 adds the animation side. Emitting buffers the event and asks the JS thread to drain, so however many events land before the drain runs arrive in a single JS call. That keeps the JS call off the UI thread and out of the registry lock. A drain is requested per event rather than latched per batch: a request can be dropped before it runs, and there is no signal for that, so anything remembering that one is outstanding would strand the buffer for good. `elapsedTime` is converted to seconds once, matching the contract already shipped on web. The event type ordinals are the bit indices of the subscription mask, so the JS constants have to stay in sync with them. The four transition values are reserved and unemitted until CSS transitions land.
174de44 to
86605c4
Compare
The event carries seconds, so reusing elapsedTime for both meant the same name changed units mid-chain. Also drops the Observer alias, which had one user left, and an include nothing used.
Reports CSS animation events from the engine. The run lifecycle already tracks the milestones a run crosses, so this maps each one to its event and emits it with the time elapsed by then.
Which time that is comes from the phase change rather than the milestone, so a start entering from a delay reports the interval start and one re-entering a finished run reports the interval end. A run made infinite after it had finished reports an unbounded one, as on the web.
Subscription is a bitmask travelling with the animation config a view already sends, so a view without callbacks installs no reporter and emits nothing.
Loop-driven animations only, which is all of them today:
platformAnimationFactoryhas no implementation on any platform.