feat(frontend): add Motion transitions for template chip + sessions - #5252
Conversation
The chip morph was hand-rolled: an off-flow ghost measured by a ResizeObserver drove an explicit width onto the visible chip, with CSS transitions for the width/opacity/fade. It only animated the container — switching templates snapped the initials, name, and provider logos. Rebuild it on Motion (already a dep, previously unused): - the chip's `layout` prop morphs the auto width (a no-bounce spring via the visualDuration/bounce API, so the 1.5px seam border never overshoots), deleting the ghost, ResizeObserver, useLayoutEffect, and width state; - an inner AnimatePresence keyed on the template transitions the whole content group (badge + name + logos), so the content swaps instead of snapping; - AnimatePresence in the dock owns the fade/rise on select/clear; - MotionConfig reducedMotion="user" collapses the transform/layout animations to plain opacity for users who ask for reduced motion.
The playground shows the same sessions two ways — compact tags in the build-mode bar, list rows in the chat-mode rail — and neither entered or left with any motion (the rail hand-rolled a grid-collapse + rAF + setTimeout delete-defer; the bar just snapped). Add a coordinated Motion group across both. - shared assets/sessionMotion.ts holds one SESSION_SPRING plus the tag/row variants, so a session's two representations enter and leave with identical physics — the "connected" feel between the bar and the rail; - each item collapses its OWN size in step with its fade (rows their height, tags their width) so a neighbour closes the gap as one continuous motion rather than a pop-then-reflow two-step, and the inter-item gap is an animated margin that collapses to nothing with the item so nothing snaps on unmount; - deleting a rail row is now immediate — AnimatePresence plays the exit — replacing the leavingIds/deleteTimersRef/220ms-timer machinery; - MotionConfig reducedMotion="user" honours the OS setting on both.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
🚧 Files skipped from review as they are similar to previous changes (6)
📝 WalkthroughSummary by CodeRabbit
WalkthroughMotion-based transitions are added for session rail rows, session tags, and template chips. Shared spring and variant definitions replace timer- and measurement-driven animations, with presence handling, layout morphing, keyed crossfades, and reduced-motion support. ChangesMotion UI animations
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant SessionRail
participant AnimatePresence
participant SessionRailRow
SessionRail->>AnimatePresence: Render session rows
AnimatePresence->>SessionRailRow: Mount or unmount rows
SessionRailRow->>SessionRailRow: Apply ROW_VARIANTS and SESSION_SPRING
sequenceDiagram
participant TemplateChipDock
participant AnimatePresence
participant TemplateChip
TemplateChipDock->>AnimatePresence: Render visible template chip
AnimatePresence->>TemplateChip: Animate mount or unmount
TemplateChip->>TemplateChip: Morph layout and crossfade keyed content
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 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 |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
🧹 Nitpick comments (4)
web/oss/src/components/TemplateStrip/components/TemplateChip.tsx (1)
13-30: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winTrim the animation implementation comments.
These new comment blocks substantially exceed the one-short-line rule. Retain only the non-obvious Motion scale-correction rationale.
Proposed cleanup
-// Modern spring API: `visualDuration` is when the bulk of the width morph lands; `bounce: 0` -// keeps the 1.5px border from overshooting its target width. Timed to the content crossfade. +// Align the width spring with the content crossfade without overshoot. -/** - * Provenance chip docked above the composer ("From template: <name>"). No bottom border — - * it sits flush against the composer's top edge (adjacent siblings, no gap). - * - * Two Motion transitions run on a template switch: - * - the container's `layout` spring morphs the chip's auto width (CSS `transition-[width]` couldn't); - * - an inner `AnimatePresence` (keyed on the template) crossfades the WHOLE content group — - * initials badge, name, and provider logos — so they swap rather than snap. `popLayout` pulls - * the outgoing group out of flow so the container can measure + morph to the incoming width. - * `LayoutGroup` coordinates the exit + layout animations; the ✕ lives outside the presence so it - * stays put while the content swaps. Reduced-motion handling lives in the parent MotionConfig. - */ +/** Crossfade template content while the chip width morphs. */ -// border-radius via style so Motion scale-corrects it during the width morph (Tailwind -// classes aren't corrected). `relative` gives popLayout a non-static positioning parent. -// The tint composites over the composer base so the bg stays opaque -// (--ag-strip-selected-bg is 6%-alpha in dark) and the overlap hides its border. +// Inline radius lets Motion scale-correct the layout transform.As per coding guidelines, “Keep in-code comments to one short line maximum unless a genuinely surprising constraint requires a brief exception.”
Also applies to: 44-47
Source: Coding guidelines
web/oss/src/components/TemplateStrip/components/TemplateChipDock.tsx (1)
17-24: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winCondense the new dock documentation.
This repeats implementation mechanics over eight lines; keep a single concise description.
Proposed cleanup
-/** - * Docks the provenance chip above the composer. AnimatePresence fades + rises the chip as it - * mounts/unmounts; the chip's own `layout` morphs its width when the template switches. During - * the exit the caller keeps passing the last template, so it fades out with its real content. - * - * `MotionConfig reducedMotion="user"` respects the OS setting: transform + layout animations - * (the rise and the width morph) collapse to instant, leaving only the opacity crossfades. - */ +/** Animates chip presence while TemplateChip handles template width changes. */As per coding guidelines, “Keep in-code comments to one short line maximum unless a genuinely surprising constraint requires a brief exception.”
Source: Coding guidelines
web/oss/src/components/TemplateStrip/hooks/useTemplateProvenance.tsx (1)
108-111: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAttribute the width morph to
TemplateChip.
TemplateChipDockowns presence fade/rise only;TemplateChipownslayoutandWIDTH_SPRING. Make the comment both accurate and concise.Proposed cleanup
-// During the exit `selectedTemplate` is already null, so we show the retained last template -// (falling back to the registry's first only for the very first, never-picked render) — the -// chip fades out with its real content. TemplateChipDock owns the AnimatePresence fade/rise -// and the width-morph; passing `visible` drives them. +// Retain the last template for exit; TemplateChipDock handles presence and TemplateChip width.As per coding guidelines, “Keep in-code comments to one short line maximum unless a genuinely surprising constraint requires a brief exception.”
Source: Coding guidelines
web/oss/src/components/AgentChatSlice/components/SessionRail.tsx (1)
200-225: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winKeep
AnimatePresencemounted across the empty states
Mounting it only in the non-empty branch skips the rowexitanimation when the last session is deleted or the search filters everything out. Move the empty/mismatch rendering outside the presence block so the final row can animate out.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 7690b53b-08ae-4744-a011-578cd7412de2
📒 Files selected for processing (6)
web/oss/src/components/AgentChatSlice/assets/sessionMotion.tsweb/oss/src/components/AgentChatSlice/components/SessionRail.tsxweb/oss/src/components/AgentChatSlice/components/SessionTagBar.tsxweb/oss/src/components/TemplateStrip/components/TemplateChip.tsxweb/oss/src/components/TemplateStrip/components/TemplateChipDock.tsxweb/oss/src/components/TemplateStrip/hooks/useTemplateProvenance.tsx
- SessionRail: keep AnimatePresence always mounted (render the empty/no-match states as siblings) so the last row still plays its exit when the session list is emptied by a delete or filtered to nothing. - Trim the new animation comments to the repo's one-line rule and correct the width-morph attribution (TemplateChip owns it, not TemplateChipDock).
|
@coderabbitai review |
✅ Action performedReview finished.
|
Context
Two spots in the agent experience changed with no motion, or with hand-rolled animation code. On the home composer, switching templates snapped the provenance chip's width and swapped its content instantly. In the playground, session items had no coordinated enter/exit: the chat-mode rail hand-rolled a grid-collapse plus a rAF reveal plus a 220ms
setTimeoutdelete-defer, and the build-mode tag bar just popped.This is the first batch of moving those onto Motion (the
motionpackage was already a dependency but unused until now).Changes
Two independent, file-disjoint pieces (one commit each).
Template chip (
TemplateStrip/)layout. CSStransition-[width]can't animate an auto width, which is why the old code measured an off-flow ghost with a ResizeObserver and drove an explicit width. All of that machinery is deleted.AnimatePresence, instead of snapping.AnimatePresenceowns the chip's fade/rise on select and clear.Agent sessions (
AgentChatSlice/)assets/sessionMotion.tsholds one shared spring plus the tag/row variants, so a session's tag (bar) and row (rail) enter and leave with identical physics.AnimatePresenceplays the exit. This replaces theleavingIds/deleteTimersRef/ 220ms-timer bookkeeping.Both surfaces are wrapped in
MotionConfig reducedMotion="user", so the transform and layout animations degrade to plain opacity when the OS asks for reduced motion.Tests / notes
pnpm lint-fixclean across the workspace.visualDuration/bounce) andreducedMotionare type-checked against the installedmotion@12.38.0.What to QA