UNPKG

@oiij/use

Version:

Som Composable Functions for Vue 3

46 lines (44 loc) 1.82 kB
import { nextTick } from "vue"; //#region src/composables/use-view-transition.ts const styleText = ` ::view-transition-old(root),::view-transition-new(root){ animation: none; mix-blend-mode: normal; } ::view-transition-old(root),._::view-transition-new(root){ z-index: 1; } ::view-transition-new(root),._::view-transition-old(root){ z-index: 2147483646; }`; function useViewTransition(options) { const isAppearanceTransition = typeof document !== "undefined" && !!document.startViewTransition && !window.matchMedia("(prefers-reduced-motion: reduce)").matches; const { duration = 300, easing = "linear", effect = true, reverseSelector = ".dark" } = options ?? {}; if (typeof document !== "undefined" && !document.querySelector("style[vts-id=\"view-transition-style\"]")) { const style = document.createElement("style"); style.setAttribute("vts-id", "view-transition-style"); style.appendChild(document.createTextNode(styleText.replaceAll("._", reverseSelector))); document.head.appendChild(style); } async function run(cb, opt) { const { reverse = false, x = 0, y = 0 } = opt ?? {}; const endRadius = Math.hypot(Math.max(x, innerWidth - x), Math.max(y, innerHeight - y)); const clipPath = [`circle(0px at ${x}px ${y}px)`, `circle(${endRadius}px at ${x}px ${y}px)`]; if (!isAppearanceTransition || !effect) { if (typeof cb === "function") await Promise.try(cb); return; } await document.startViewTransition(async () => { if (typeof cb === "function") await Promise.try(cb); await nextTick(); }).ready; await document.documentElement.animate({ clipPath: reverse ? clipPath.reverse() : clipPath }, { duration, easing, pseudoElement: `::view-transition-${reverse ? "old" : "new"}(root)` }).finished; } return { run }; } //#endregion export { useViewTransition };