sonner.tsx 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
  1. import { useEffect, useState } from "react"
  2. import { Toaster as Sonner } from "sonner"
  3. type ToasterProps = React.ComponentProps<typeof Sonner>
  4. const Toaster = ({ ...props }: ToasterProps) => {
  5. const [theme, setTheme] = useState<"light" | "dark">("light")
  6. useEffect(() => {
  7. // Check initial theme
  8. const isDark = document.documentElement.classList.contains("dark")
  9. setTheme(isDark ? "dark" : "light")
  10. // Watch for theme changes
  11. const observer = new MutationObserver((mutations) => {
  12. mutations.forEach((mutation) => {
  13. if (mutation.attributeName === "class") {
  14. const isDark = document.documentElement.classList.contains("dark")
  15. setTheme(isDark ? "dark" : "light")
  16. }
  17. })
  18. })
  19. observer.observe(document.documentElement, { attributes: true })
  20. return () => observer.disconnect()
  21. }, [])
  22. return (
  23. <Sonner
  24. theme={theme}
  25. className="toaster group"
  26. toastOptions={{
  27. classNames: {
  28. toast:
  29. "group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
  30. description: "group-[.toast]:text-muted-foreground",
  31. actionButton:
  32. "group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
  33. cancelButton:
  34. "group-[.toast]:bg-muted group-[.toast]:text-muted-foreground",
  35. },
  36. }}
  37. {...props}
  38. />
  39. )
  40. }
  41. export { Toaster }