diff --git a/apps/www/registry/magicui/animated-theme-toggler.tsx b/apps/www/registry/magicui/animated-theme-toggler.tsx index f896fbcdf..7d1f7bcb0 100644 --- a/apps/www/registry/magicui/animated-theme-toggler.tsx +++ b/apps/www/registry/magicui/animated-theme-toggler.tsx @@ -1,6 +1,7 @@ "use client" -import { useCallback, useEffect, useRef, useState } from "react" +import type React from "react" +import { useEffect, useRef, useState } from "react" import { Moon, Sun } from "lucide-react" import { flushSync } from "react-dom" @@ -34,41 +35,54 @@ export const AnimatedThemeToggler = ({ return () => observer.disconnect() }, []) - const toggleTheme = useCallback(async () => { + const toggleTheme = () => { if (!buttonRef.current) return - await document.startViewTransition(() => { - flushSync(() => { - const newTheme = !isDark - setIsDark(newTheme) - document.documentElement.classList.toggle("dark") - localStorage.setItem("theme", newTheme ? "dark" : "light") + const supportsViewTransitions = + typeof document !== "undefined" && "startViewTransition" in document + + const newTheme = !isDark + setIsDark(newTheme) + localStorage.setItem("theme", newTheme ? "dark" : "light") + + + if (supportsViewTransitions) { + const transition = (document as any).startViewTransition(() => { + flushSync(() => { + document.documentElement.classList.toggle("dark") + }) + }) + + transition.ready.then(() => { + if (!buttonRef.current) return + + const { top, left, width, height } = + buttonRef.current.getBoundingClientRect() + const x = left + width / 2 + const y = top + height / 2 + const maxRadius = Math.hypot( + Math.max(left, window.innerWidth - left), + Math.max(top, window.innerHeight - top) + ) + + document.documentElement.animate( + { + clipPath: [ + `circle(0px at ${x}px ${y}px)`, + `circle(${maxRadius}px at ${x}px ${y}px)`, + ], + }, + { + duration, + easing: "ease-in-out", + pseudoElement: "::view-transition-new(root)", + } + ) }) - }).ready - - const { top, left, width, height } = - buttonRef.current.getBoundingClientRect() - const x = left + width / 2 - const y = top + height / 2 - const maxRadius = Math.hypot( - Math.max(left, window.innerWidth - left), - Math.max(top, window.innerHeight - top) - ) - - document.documentElement.animate( - { - clipPath: [ - `circle(0px at ${x}px ${y}px)`, - `circle(${maxRadius}px at ${x}px ${y}px)`, - ], - }, - { - duration, - easing: "ease-in-out", - pseudoElement: "::view-transition-new(root)", - } - ) - }, [isDark, duration]) + } else { + document.documentElement.classList.toggle("dark") + } + } return (