fix(mobile): sent messages rise into place instead of dropping in#28660
Problem
A message you send from the mobile composer drops into the feed from above instead of rising up from the composer.
Reanimated names its entering presets after the side they start from. In react-native-reanimated 4.7.1 (src/layoutReanimation/defaultAnimations/Fade.ts), FadeInUp starts at translateY: -25 and moves down to 0, while FadeInDown starts at translateY: 25 and moves up to 0. The user-message bubble in ThreadFeed.tsx used FadeInUp.duration(220), so it enters from above its resting position, away from the composer it was just sent from.
Repro: open any thread in the iOS app, send any message, and watch the new bubble.
Change
apps/mobile/src/features/threads/ThreadFeed.tsx: useFadeInDown.duration(220)for the user-message bubble entering animation and swap the import.apps/mobile/src/lib/filePreview.test.ts: addFadeInDownto thereact-native-reanimatedmock. That test rendersThreadFeed, and its mock only definedFadeInandFadeInUp.
The composer-adjacent elements in ThreadDetailScreen.tsx already enter with FadeInDown, so this makes the sent bubble consistent with them. PendingUserInputCard.tsx uses a FadeInUp/FadeOutDown pair on purpose and is intentionally untouched.
Scope and approval
This is a very small, focused fix for an obvious bug: one preset swap plus the matching test mock, nothing else. It does not change a product default or add behavior, only which way an existing 220 ms animation travels, so it qualifies for the very-small-fix exception without a prior issue or discussion.
Verification
Setup. iPhone 18 Pro simulator, iOS 27.2. Debug dev-client build of the development app variant against Metro, paired to a seeded showcase environment (scripts/mobile-showcase.ts). I opened a seeded thread and sent short messages. Screen recordings are 30 fps, so the 220 ms animation spans about 7 frames. I stepped through frames with ffmpeg.
Method note. In the normal flow (keyboard up) the keyboard dismisses and the list repositions at the same instant as the send, so the bubble's net on-screen motion is dominated by that and does not isolate the preset. I therefore also recorded a controlled flow: type the message, dismiss the keyboard, scroll the list to the end, then tap Send. Both builds were recorded in the same way, the unmodified code first and then this change, with a full JS reload each time.
Before (unmodified main).
- Keyboard up, two takes: the new bubble first appears faint with a "Pending" label near the top of the list, well above its final slot, and travels down while fading in.
- Keyboard dismissed first (controlled flow): the bubble first appears about 25 pt above its resting slot (relative to the previous message) and moves down into place.
After (this change).
- Keyboard dismissed first (controlled flow): the bubble first appears about 23 pt below its resting slot and rises into place, a mirror image of the before take. These are approximate offsets read from the frames, accurate to a few points.
- Keyboard up: the starting offset is smaller than before, but the bubble still travels downward on screen because of the keyboard and list movement described above. I could not show a clean "rises" in that flow, only in the controlled one.
Tests and checks.
vp test run src/lib/filePreview.test.ts(fromapps/mobile): 1 file, 89 tests passed.vp run check:changed: format, lint, knip, the changed test file and the React Compiler check passed. Typecheck failed in my local environment: 404tscerrors, mostly "could not find a declaration file for module 'react'" from my local install. The error set is identical on unmodifiedmain(I diffed the two outputs), so the change adds none. I could not get a clean local typecheck.
Not checked. Android, a physical device, reduced-motion settings, and messages that arrive from another client (I only exercised messages sent from this device).
Before/after recordings:
Maintainer verification: Pixel 9, keyboard dismissed before Send, ⅓ speed. Compare the bubble to the preceding row: the whole feed can move independently. A separate iPhone 18 Pro capture confirms the keyboard-open send still repositions the feed as described above.
Sent bubble entering from above before, and from below after.
Claude Sonnet 5.5 and Claude Opus 5.5 in Claude Code
🤖 Generated with Claude Code
Checks
Added 1 commit
- fix(mobile): sent messages rise into place instead of dropping in7c66c82
Approvability
Verdict: Approved at 7c66c82
Macroscope's review found this PR approvable — Fresh messages now rise into place rather than drop in, preserving the existing animation duration and eligibility. The change is presentation-only and does not affect message sending or stored data.
You can add or adjust custom eligibility rules. Learn more.
No actionable comments were generated in the recent review.
External image Recent review info
-
External image Run configuration
- Source mode: Auto
- Repository: pingdotgg/t3code
- Branch: main
- File: .coderabbit.config.ts
- Commit: 8760d06
- Layers: Repository TS config
- Review profile: CHILL
- Plan: Advanced
- Run ID:
4e1e7ce0-f8c9-45e5-93a5-d3e513c92089
External image Commits
Reviewing files that changed from the base of the PR and between 8760d063e903406c8e8f695b0852c0a15fc1e00f and 7c66c82fb2f10a28ae592a90b7da90ad65ef534f.
External image Files selected for processing: 2
apps/mobile/src/features/threads/ThreadFeed.tsxapps/mobile/src/lib/filePreview.test.ts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.
Walkthrough
Fresh user messages in the thread feed now enter with
FadeInDowninstead ofFadeInUp. The freshness condition and 220 ms duration remain unchanged. The test mock addsFadeInDown.Changes: Thread message entry animation
Layer / File(s) Summary Fresh-message animation
apps/mobile/src/features/threads/ThreadFeed.tsx,apps/mobile/src/lib/filePreview.test.tsFresh user messages use FadeInDowninstead ofFadeInUp. The test mock addsFadeInDownusing the shared transition stub.Estimated code review effort: 2 (Simple) | ~5 minutes
Change: Bug fix
Suggested reviewers:
juliusmarminge
Merge Risk: External image Minimal · up to 7c66c
The animation update is localized and carries no identified merge-blocking risk.
Pre-merge checks: Passed 4
Check name Status Explanation Title check Passed The title clearly describes the main change: correcting the mobile sent-message animation so it rises into place. It is concise and uses a conventional commit format. Description check Passed The description includes all required sections. It explains the problem and reproduction steps, identifies the code changes and scope, documents controlled before/after animation checks, reports test … Linked Issues check Passed Check skipped because no linked issues were found for this pull request. Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request. Full details: Description check
Explanation
The description includes all required sections. It explains the problem and reproduction steps, identifies the code changes and scope, documents controlled before/after animation checks, reports test results and the local typecheck limitation, and lists unverified scenarios.
Finishing Touches
Generate unit tests (beta)
- Create a new PR
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Verified the preset change on the reviewed head against its parent. On the Pixel recording the bubble now rises relative to the previous row; the iPhone keyboard-open flow still moves the feed during dismissal, which is separate from this fix. The focused mobile suite passed all 89 tests.