feat(router-core): replay view transitions on browser Back/Forward#7697
feat(router-core): replay view transitions on browser Back/Forward#7697KurtGokhan wants to merge 3 commits into
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (5)
✅ Files skipped from review due to trivial changes (2)
🚧 Files skipped from review as they are similar to previous changes (3)
📝 WalkthroughWalkthroughAdds a router option to replay opted-in view transitions during browser Back/Forward traversal, stores transition state per history entry in memory, and updates the React view-transitions example to use a direction-aware helper. ChangesReplay view transitions on traversal
Sequence Diagram(s)sequenceDiagram
participant BrowserHistory
participant RouterCore
participant viewTransitionsByIndex
participant document.startViewTransition
BrowserHistory->>RouterCore: traversal history action
RouterCore->>RouterCore: load()
RouterCore->>RouterCore: recordOrReplayViewTransition(historyAction)
RouterCore->>viewTransitionsByIndex: read or store transition by index
RouterCore->>document.startViewTransition: replay opted-in transition
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Suggested labels
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 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 |
Add the opt-in `replayViewTransitionOnTraversal` router option. The router
records the view-transition value each history entry was committed with (in
memory, keyed by __TSR_index) and replays it on BACK/FORWARD/GO, so a
transition opted into via <Link viewTransition> / navigate({ viewTransition })
no longer hard-cuts on browser Back/Forward. Includes tests, docs and a changeset.
f15254d to
b640f6b
Compare
…ample Enable replayViewTransitionOnTraversal in the view-transitions example and make its links direction-aware via a page-order-based types function, so browser Back/Forward replay the transition in the correct direction.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
examples/react/view-transitions/src/directionAwareTransition.ts (1)
33-34: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winWrap the early return in braces.
Line 34 violates the repo’s JS/TS control-flow style rule.
Suggested change
types: ({ fromLocation, toLocation }) => { - if (!fromLocation) return ['slide-left'] + if (!fromLocation) { + return ['slide-left'] + } const from = pageRank(fromLocation.pathname)As per coding guidelines,
**/*.{ts,tsx,js,jsx}: Always use curly braces forif,else, loops, and similar control statements. Never write one-line bodies likeif (foo) x = 1.🤖 Prompt for 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. In `@examples/react/view-transitions/src/directionAwareTransition.ts` around lines 33 - 34, The early return in directionAwareTransition’s types callback uses a one-line if without braces, which violates the repo’s control-flow style. Update the conditional in the fromLocation check to use curly braces around the return statement, matching the required JS/TS style used throughout the codebase and keeping the logic in the same types function.Source: Coding guidelines
packages/router-core/tests/view-transition-traversal.test.ts (1)
63-189: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd coverage for the remaining documented traversal cases.
This suite never exercises
history.go(), and it also doesn't lock down the “does not affect defaultViewTransition” contract. SincerecordOrReplayViewTransition()handlesGOin the same traversal branch and intentionally falls back todefaultViewTransitionwhen nothing is recorded, a focused case for each would make the new contract much harder to regress.🤖 Prompt for 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. In `@packages/router-core/tests/view-transition-traversal.test.ts` around lines 63 - 189, Add test coverage in replayViewTransitionOnTraversal for the missing traversal cases: exercise history.go() through the same traversal path used by traverse(), and add a case that verifies recordOrReplayViewTransition() falls back to defaultViewTransition when no recorded transition exists. Use the existing router.navigate, traverse, and startViewTransitionSpy setup in this suite so the GO branch and the defaultViewTransition contract are both explicitly locked down.
🤖 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/router-core/src/router.ts`:
- Around line 283-289: The option description in router.ts is too broad about
what is replayed on Back/Forward traversals; update the docs on the option and
the mirrored changeset text to say it only replays explicit per-navigation
`viewTransition` opt-ins from `<Link viewTransition>` or `navigate({
viewTransition })`, while traversals without that still use
`defaultViewTransition` via `startViewTransition()`. Keep the wording aligned
with the `defaultViewTransition` behavior and reference the relevant option
block in `router.ts` so the clarification stays consistent.
---
Nitpick comments:
In `@examples/react/view-transitions/src/directionAwareTransition.ts`:
- Around line 33-34: The early return in directionAwareTransition’s types
callback uses a one-line if without braces, which violates the repo’s
control-flow style. Update the conditional in the fromLocation check to use
curly braces around the return statement, matching the required JS/TS style used
throughout the codebase and keeping the logic in the same types function.
In `@packages/router-core/tests/view-transition-traversal.test.ts`:
- Around line 63-189: Add test coverage in replayViewTransitionOnTraversal for
the missing traversal cases: exercise history.go() through the same traversal
path used by traverse(), and add a case that verifies
recordOrReplayViewTransition() falls back to defaultViewTransition when no
recorded transition exists. Use the existing router.navigate, traverse, and
startViewTransitionSpy setup in this suite so the GO branch and the
defaultViewTransition contract are both explicitly locked down.
🪄 Autofix (Beta)
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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 66f6fb48-390e-4f1e-b114-e92c53beda02
📒 Files selected for processing (9)
.changeset/replay-view-transition-on-traversal.mddocs/router/api/router/RouterOptionsType.mdexamples/react/view-transitions/src/directionAwareTransition.tsexamples/react/view-transitions/src/main.tsxexamples/react/view-transitions/src/routes/explore.tsxexamples/react/view-transitions/src/routes/how-it-works.tsxexamples/react/view-transitions/src/routes/index.tsxpackages/router-core/src/router.tspackages/router-core/tests/view-transition-traversal.test.ts
…ult-fallback tests - Clarify in JSDoc/docs/changeset that without the option only per-navigation viewTransition opt-ins are not replayed; traversals still fall back to defaultViewTransition. - Add curly braces to the example helper's early return (repo style) + docstring. - Add tests for a multi-step history.go() traversal and the defaultViewTransition fallback contract.
Problem
View transitions only fire for navigations that go through
commitLocation—<Link viewTransition>ornavigate({ viewTransition }), which setrouter.shouldViewTransitionright before pushing to history. Browser Back/Forward arrives aspopstate(the history subscriber isrouter.load, actionBACK | FORWARD | GO) and never passes throughcommitLocation, so the flag stays unset and no transition plays.Result: an app animates
A → Bvia aLink, but pressing Back gives a hard cut. The only workaround today isdefaultViewTransition, which animates every navigation — you can't opt one flow in and have it round-trip.Solution
A new opt-in router option, default
false:The router records the view-transition value each entry was committed with (keyed by
__TSR_index) and replays it on traversal:PUSH/REPLACE: record the currentshouldViewTransitionfor the arriving index (truthy values only, so it never short-circuitsdefaultViewTransition).BACK/FORWARD/GO: beforestartViewTransitionreads the flag inonReady, setshouldViewTransition = shouldViewTransition ?? recorded(leaving) ?? recorded(arriving).Checking both endpoints makes replay symmetric — a transition opted into on
A → Bplays on bothB → A(back) and a laterA → B(forward) — and an explicitly-set value is never clobbered. It lives inrouter-core'sload, the single point that sees the history action for every navigation kind, so no subscriber-ordering tricks are needed. No-op when off / on the server.Why in-memory rather than
history.stateViewTransitionOptions.typescan be a function, which is not structured-cloneable, so it can't be written tohistory.state. An in-memoryMappreserves it by reference; the only cost is losing flags across a hard reload (degrades to no transition).Open questions for maintainers
replayViewTransitionOnTraversal, or fold intodefaultViewTransition?Tests
packages/router-core/tests/view-transition-traversal.test.ts: replay on back, replay on forward, plain edge → no transition, explicit value not clobbered,ViewTransitionOptionsobject (incl. functionaltypes) preserved by identity, only the transitioned entry replays, and off-by-default.Demo
StackBlitz: ts-router-view-transition-replay (NOT READY YET) — navigate Home → Details → About (each link animates), then use the browser Back/Forward buttons. Toggle the
replayViewTransitionOnTraversalcheckbox to compare: on = transitions replay, off = hard cut. (Best viewed in a Chromium browser.)I also tested the feature in one of the examples and verified that the transition is direction aware. This required some changes on the example project and I pushed those too.
Google.Chrome-.Vite.App-000782.mp4
Docs & changeset
Added a
replayViewTransitionOnTraversalentry to the router options docs and a changeset.AI Usage Disclosure
I used AI for generating the changes in this PR, and most of the PR description. But the initial plan was mine and I reviewed the plan and every single line of code committed, and tried to steer AI away from making bad decisions.
Summary by CodeRabbit
replayViewTransitionOnTraversaloption and clarified its behavior, defaults, and reload behavior.