Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions packages/router-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ export {
} from './router'

export type {
LocationChangeInfo,
ViewTransitionOptions,
TrailingSlashOption,
Register,
Expand Down
101 changes: 74 additions & 27 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 @@ -766,16 +787,18 @@ export type AnyRouterWithContext<TContext> = RouterCore<

export type AnyRouter = RouterCore<any, any, any, any, any>

export interface LocationChangeInfo {
fromLocation?: ParsedLocation
toLocation: ParsedLocation
pathChanged: boolean
hrefChanged: boolean
hashChanged: boolean
}

export interface ViewTransitionOptions {
types:
| Array<string>
| ((locationChangeInfo: {
fromLocation?: ParsedLocation
toLocation: ParsedLocation
pathChanged: boolean
hrefChanged: boolean
hashChanged: boolean
}) => Array<string> | false)
| ((locationChangeInfo: LocationChangeInfo) => Array<string> | false)
}

// TODO where is this used? can we remove this?
Expand Down Expand Up @@ -819,7 +842,7 @@ export type TrailingSlashOption =
export function getLocationChangeInfo(routerState: {
resolvedLocation?: ParsedLocation
location: ParsedLocation
}) {
}): LocationChangeInfo {
const fromLocation = routerState.resolvedLocation
const toLocation = routerState.location
const pathChanged = fromLocation?.pathname !== toLocation.pathname
Expand Down Expand Up @@ -2088,22 +2111,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,7 +2136,6 @@ 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 () => {
Expand Down Expand Up @@ -2256,21 +2277,21 @@ export class RouterCore<
// TODO: Fix this when dom types are updated
let startViewTransitionParams: any

const next = this.latestLocation
const prevLocation = this.state.resolvedLocation

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

if (
typeof shouldViewTransition === 'object' &&
this.isViewTransitionTypesSupported
) {
const next = this.latestLocation
const prevLocation = this.state.resolvedLocation

const resolvedViewTransitionTypes =
typeof shouldViewTransition.types === 'function'
? shouldViewTransition.types(
getLocationChangeInfo({
resolvedLocation: prevLocation,
location: next,
}),
)
? shouldViewTransition.types(locationChangeInfo)
: shouldViewTransition.types

if (resolvedViewTransitionTypes === false) {
Expand All @@ -2286,7 +2307,33 @@ export class RouterCore<
startViewTransitionParams = fn
}

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