11<script setup lang="ts">
2- import { computed , onMounted , onUnmounted , ref } from " vue" ;
2+ import { computed , nextTick , onMounted , onUnmounted , ref } from " vue" ;
33import { cn } from " ../../../lib/utils" ;
44
55export type TransitionVariant =
@@ -37,7 +37,7 @@ const emit = defineEmits<{
3737}>();
3838
3939type ViewTransitionDocument = Document & {
40- startViewTransition? : (callback : () => void ) => {
40+ startViewTransition? : (callback : () => void | Promise < void > ) => {
4141 ready: Promise <void >;
4242 finished: Promise <void >;
4343 };
@@ -161,15 +161,16 @@ function getThemeTransitionClipPaths(
161161
162162const applyTheme = () => {
163163 const newIsDark = ! isDark .value ;
164- // Always toggle the class synchronously so the View Transitions API
165- // snapshots the new theme inside the startViewTransition callback.
166- document .documentElement .classList .toggle (" dark" );
164+
167165 if (isControlled .value ) {
168166 emit (" themeChange" , newIsDark ? " dark" : " light" );
169- } else {
170- internalIsDark .value = newIsDark ;
171- localStorage .setItem (" theme" , newIsDark ? " dark" : " light" );
167+ return ;
172168 }
169+
170+ // Keep DOM class in sync before view-transition snapshots in uncontrolled mode.
171+ document .documentElement .classList .toggle (" dark" , newIsDark );
172+ internalIsDark .value = newIsDark ;
173+ localStorage .setItem (" theme" , newIsDark ? " dark" : " light" );
173174};
174175
175176const toggleTheme = () => {
@@ -178,7 +179,11 @@ const toggleTheme = () => {
178179
179180 const doc = document as ViewTransitionDocument ;
180181
181- if (typeof doc .startViewTransition !== " function" ) {
182+ const prefersReducedMotion =
183+ typeof window .matchMedia === " function" &&
184+ window .matchMedia (" (prefers-reduced-motion: reduce)" ).matches ;
185+
186+ if (prefersReducedMotion || typeof doc .startViewTransition !== " function" ) {
182187 applyTheme ();
183188 return ;
184189 }
@@ -220,7 +225,10 @@ const toggleTheme = () => {
220225 root .style .removeProperty (" --spark-theme-vt-clip-from" );
221226 };
222227
223- const transition = doc .startViewTransition (applyTheme );
228+ const transition = doc .startViewTransition (async () => {
229+ applyTheme ();
230+ await nextTick ();
231+ });
224232 transition .finished .finally (cleanup );
225233
226234 transition .ready .then (() => {
0 commit comments