/
view-transitions.client.ts
56 lines (45 loc) · 1.4 KB
/
view-transitions.client.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import { useRouter } from '#app/composables/router'
import { defineNuxtPlugin } from '#app/nuxt'
export default defineNuxtPlugin((nuxtApp) => {
if (!document.startViewTransition) { return }
let finishTransition: undefined | (() => void)
let abortTransition: undefined | (() => void)
const router = useRouter()
router.beforeResolve((to, from) => {
if (to === from || to.matched.every((comp, index) => comp.components && comp.components?.default === from.matched[index]?.components?.default)) {
return
}
const promise = new Promise<void>((resolve, reject) => {
finishTransition = resolve
abortTransition = reject
})
let changeRoute: () => void
const ready = new Promise<void>(resolve => (changeRoute = resolve))
const transition = document.startViewTransition!(() => {
changeRoute()
return promise
})
transition.finished.then(() => {
abortTransition = undefined
finishTransition = undefined
})
return ready
})
nuxtApp.hook('vue:error', () => {
abortTransition?.()
abortTransition = undefined
})
nuxtApp.hook('page:finish', () => {
finishTransition?.()
finishTransition = undefined
})
})
declare global {
interface Document {
startViewTransition?: (callback: () => Promise<void> | void) => {
finished: Promise<void>
updateCallbackDone: Promise<void>
ready: Promise<void>
}
}
}