Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 57 additions & 1 deletion docs/router/framework/react/api/router/RouterEventsType.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,39 @@ type RouterEvents = {
toLocation: ParsedLocation
pathChanged: boolean
hrefChanged: boolean
hashChanged: boolean
}
onBeforeLoad: {
type: 'onBeforeLoad'
fromLocation?: ParsedLocation
toLocation: ParsedLocation
pathChanged: boolean
hrefChanged: boolean
hashChanged: boolean
}
onLoad: {
type: 'onLoad'
fromLocation?: ParsedLocation
toLocation: ParsedLocation
pathChanged: boolean
hrefChanged: boolean
hashChanged: boolean
}
onResolved: {
type: 'onResolved'
fromLocation?: ParsedLocation
toLocation: ParsedLocation
pathChanged: boolean
hrefChanged: boolean
hashChanged: boolean
}
onBeforeRouteMount: {
type: 'onBeforeRouteMount'
fromLocation?: ParsedLocation
toLocation: ParsedLocation
pathChanged: boolean
hrefChanged: boolean
hashChanged: boolean
}
onInjectedHtml: {
type: 'onInjectedHtml'
Expand All @@ -50,6 +55,45 @@ type RouterEvents = {
type: 'onRendered'
fromLocation?: ParsedLocation
toLocation: ParsedLocation
pathChanged: boolean
hrefChanged: boolean
hashChanged: boolean
}
onViewTransitionStart: {
type: 'onViewTransitionStart'
transition: ViewTransition
fromLocation?: ParsedLocation
toLocation: ParsedLocation
pathChanged: boolean
hrefChanged: boolean
hashChanged: boolean
}
onViewTransitionReady: {
type: 'onViewTransitionReady'
transition: ViewTransition
fromLocation?: ParsedLocation
toLocation: ParsedLocation
pathChanged: boolean
hrefChanged: boolean
hashChanged: boolean
}
onViewTransitionUpdateCallbackDone: {
type: 'onViewTransitionUpdateCallbackDone'
transition: ViewTransition
fromLocation?: ParsedLocation
toLocation: ParsedLocation
pathChanged: boolean
hrefChanged: boolean
hashChanged: boolean
}
onViewTransitionFinish: {
type: 'onViewTransitionFinish'
transition: ViewTransition
fromLocation?: ParsedLocation
toLocation: ParsedLocation
pathChanged: boolean
hrefChanged: boolean
hashChanged: boolean
}
}
```
Expand All @@ -60,7 +104,7 @@ Once an event is emitted, the following properties will be present on the event

### `type` property

- Type: `onBeforeNavigate | onBeforeLoad | onLoad | onBeforeRouteMount | onResolved`
- Type: `onBeforeNavigate | onBeforeLoad | onLoad | onBeforeRouteMount | onResolved | onRendered | onViewTransitionStart | onViewTransitionReady | onViewTransitionUpdateCallbackDone | onViewTransitionFinish`
- The type of the event
- This is useful for discriminating between events in a listener function.

Expand All @@ -84,6 +128,18 @@ Once an event is emitted, the following properties will be present on the event
- Type: `boolean`
- `true` if the href has changed between the `fromLocation` and `toLocation`.

### `hashChanged` property

- Type: `boolean`
- `true` if the hash has changed between the `fromLocation` and `toLocation`.

### `transition` property

- Type: `ViewTransition`
- Available on: `onViewTransitionStart`, `onViewTransitionReady`, `onViewTransitionUpdateCallbackDone`, `onViewTransitionFinish`
- The [ViewTransition](https://developer.mozilla.org/en-US/docs/Web/API/ViewTransition) object representing the view transition in progress.
- This property allows you to interact with the view transition lifecycle, including access to promises like `ready`, `updateCallbackDone`, and `finished`.

## Example

```tsx
Expand Down
73 changes: 61 additions & 12 deletions packages/router-core/src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,11 @@ type NavigationEventInfo = {
hashChanged: boolean
}

export type ViewTransitionEventInfo = {
// @ts-ignore -- ViewTransition support since ts 5.6
transition: ViewTransition
}

export interface RouterEvents {
onBeforeNavigate: {
type: 'onBeforeNavigate'
Expand All @@ -563,6 +568,22 @@ export interface RouterEvents {
onRendered: {
type: 'onRendered'
} & NavigationEventInfo
onViewTransitionStart: {
type: 'onViewTransitionStart'
} & ViewTransitionEventInfo &
NavigationEventInfo
onViewTransitionReady: {
type: 'onViewTransitionReady'
} & ViewTransitionEventInfo &
NavigationEventInfo
onViewTransitionUpdateCallbackDone: {
type: 'onViewTransitionUpdateCallbackDone'
} & ViewTransitionEventInfo &
NavigationEventInfo
onViewTransitionFinish: {
type: 'onViewTransitionFinish'
} & ViewTransitionEventInfo &
NavigationEventInfo
}

export type RouterEvent = RouterEvents[keyof RouterEvents]
Expand Down Expand Up @@ -827,6 +848,7 @@ export function getLocationChangeInfo(routerState: {
const hashChanged = fromLocation?.hash !== toLocation.hash
return { fromLocation, toLocation, pathChanged, hrefChanged, hashChanged }
}
export type LocationChangeInfo = ReturnType<typeof getLocationChangeInfo>

export type CreateRouterFn = <
TRouteTree extends AnyRoute,
Expand Down Expand Up @@ -2088,22 +2110,21 @@ export class RouterCore<
const next = this.latestLocation
const prevLocation = this.state.resolvedLocation

const locationChangeInfo = getLocationChangeInfo({
resolvedLocation: prevLocation,
location: next,
})

if (!this.state.redirect) {
this.emit({
type: 'onBeforeNavigate',
...getLocationChangeInfo({
resolvedLocation: prevLocation,
location: next,
}),
...locationChangeInfo,
})
}

this.emit({
type: 'onBeforeLoad',
...getLocationChangeInfo({
resolvedLocation: prevLocation,
location: next,
}),
...locationChangeInfo,
})

await loadMatches({
Expand All @@ -2114,10 +2135,9 @@ export class RouterCore<
updateMatch: this.updateMatch,
// eslint-disable-next-line @typescript-eslint/require-await
onReady: async () => {
// eslint-disable-next-line @typescript-eslint/require-await
// Wrap batch in framework-specific transition wrapper (e.g., Solid's startTransition)
this.startTransition(() => {
this.startViewTransition(async () => {
this.startViewTransition(locationChangeInfo, async () => {
// this.viewTransitionPromise = createControlledPromise<true>()

// Commit the pending matches. If a previous match was
Expand Down Expand Up @@ -2237,7 +2257,10 @@ export class RouterCore<
}
}

startViewTransition = (fn: () => Promise<void>) => {
startViewTransition = (
locationChangeInfo: LocationChangeInfo,
fn: () => Promise<void>,
) => {
// Determine if we should start a view transition from the navigation
// or from the router default
const shouldViewTransition =
Expand Down Expand Up @@ -2286,7 +2309,33 @@ export class RouterCore<
startViewTransitionParams = fn
}

document.startViewTransition(startViewTransitionParams)
const transition = document.startViewTransition(startViewTransitionParams)
this.emit({
type: 'onViewTransitionStart',
transition,
...locationChangeInfo,
})
transition.ready.then(() => {
this.emit({
type: 'onViewTransitionReady',
transition,
...locationChangeInfo,
})
})
transition.updateCallbackDone.then(() => {
this.emit({
type: 'onViewTransitionUpdateCallbackDone',
transition,
...locationChangeInfo,
})
})
transition.finished.then(() => {
this.emit({
type: 'onViewTransitionFinish',
transition,
...locationChangeInfo,
})
})
} else {
fn()
}
Expand Down
Loading