mirror of
https://github.com/hanzoai/next.js.git
synced 2026-10-30 14:46:38 +00:00
## Summary This adds a new experimental router method `experimental_gesturePush` that enables gesture-driven navigation. The feature is gated behind a new `experimental.gestureTransition` config flag, which implicitly opts the app into using the experimental React build. It is _not_ suitable for production use yet; it's a proof-of-concept so we can test the integration between the Next.js client router and React's Gesture Transitions experiment. You can use it to build demos, but it shouldn't be used in a real app. It dispatches updates through React's useOptimistic hook instead of the main router state queue, essentially forking the router state until the gesture completes. This should only be called inside `startGestureTransition`. It's a low-level method that is not meant to be used in application code, only in libraries that know how to properly integrate with both Next and React. ## Test Plan - E2E test that simulates a gesture by holding an async transition open between button clicks - Run: `pnpm testonly test/e2e/app-dir/gesture-transitions`
71 lines
2.1 KiB
TypeScript
71 lines
2.1 KiB
TypeScript
'use client'
|
|
|
|
import { ReactNode, startTransition } from 'react'
|
|
import { useRouter, usePathname } from 'next/navigation'
|
|
import Link from 'next/link'
|
|
|
|
const pendingResolvers = new Set<() => void>()
|
|
|
|
export default function Root({ children }: { children: ReactNode }) {
|
|
const router = useRouter()
|
|
const pathname = usePathname()
|
|
const isOnHomePage = pathname === '/'
|
|
|
|
const startGesture = (href: string) => {
|
|
// NOTE: In a real scenario, this would be startGestureTransition,
|
|
// not startTransition.
|
|
startTransition(async () => {
|
|
// Call gesture push to show prefetched content immediately
|
|
;(router as any).experimental_gesturePush(href)
|
|
|
|
// Create a promise that won't resolve until the "end gesture" button
|
|
// is clicked. This simulates a gesture that takes time to complete.
|
|
await new Promise<void>((resolve) => {
|
|
pendingResolvers.add(resolve)
|
|
})
|
|
|
|
// After the gesture ends, perform the canonical navigation
|
|
router.push(href)
|
|
})
|
|
}
|
|
|
|
const endGesture = () => {
|
|
// Resolve all pending gestures
|
|
for (const resolve of pendingResolvers) {
|
|
resolve()
|
|
}
|
|
pendingResolvers.clear()
|
|
}
|
|
|
|
return (
|
|
<html>
|
|
<body>
|
|
<header>
|
|
<h1>Gesture Transitions Test</h1>
|
|
<p>
|
|
This test simulates a gesture transition using two buttons. "Start
|
|
Gesture" calls <code>experimental_gesturePush</code> and begins an
|
|
async transition that doesn't complete until "End Gesture" is
|
|
clicked. This allows observing the intermediate gesture state before
|
|
the canonical navigation completes.
|
|
</p>
|
|
</header>
|
|
<nav>
|
|
<Link href="/target-page">Link to target</Link>
|
|
<button
|
|
data-testid="start-gesture"
|
|
onClick={() => startGesture('/target-page')}
|
|
disabled={!isOnHomePage}
|
|
>
|
|
Start Gesture
|
|
</button>
|
|
<button data-testid="end-gesture" onClick={endGesture}>
|
|
End Gesture
|
|
</button>
|
|
</nav>
|
|
<main>{children}</main>
|
|
</body>
|
|
</html>
|
|
)
|
|
}
|