blob: 1e09b4e152306cb68c2c287db2288fb38435e7bc [file] [log] [blame]
gio5f2f1002025-03-20 18:38:48 +04001import * as React from "react"
2import * as ToastPrimitives from "@radix-ui/react-toast"
3import { cva, type VariantProps } from "class-variance-authority"
4import { cn } from "@/lib/utils"
5import { Cross2Icon } from "@radix-ui/react-icons"
6
7const ToastProvider = ToastPrimitives.Provider
8
9const ToastViewport = React.forwardRef<
10 React.ElementRef<typeof ToastPrimitives.Viewport>,
11 React.ComponentPropsWithoutRef<typeof ToastPrimitives.Viewport>
12>(({ className, ...props }, ref) => (
13 <ToastPrimitives.Viewport
14 ref={ref}
15 className={cn(
16 "fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]",
17 className
18 )}
19 {...props}
20 />
21))
22ToastViewport.displayName = ToastPrimitives.Viewport.displayName
23
24const toastVariants = cva(
25 "group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-md border p-4 pr-6 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full",
26 {
27 variants: {
28 variant: {
29 default: "border bg-background text-foreground",
30 destructive:
31 "destructive group border-destructive bg-destructive text-destructive-foreground",
32 },
33 },
34 defaultVariants: {
35 variant: "default",
36 },
37 }
38)
39
40const Toast = React.forwardRef<
41 React.ElementRef<typeof ToastPrimitives.Root>,
42 React.ComponentPropsWithoutRef<typeof ToastPrimitives.Root> &
43 VariantProps<typeof toastVariants>
44>(({ className, variant, ...props }, ref) => {
45 return (
46 <ToastPrimitives.Root
47 ref={ref}
48 className={cn(toastVariants({ variant }), className)}
49 {...props}
50 />
51 )
52})
53Toast.displayName = ToastPrimitives.Root.displayName
54
55const ToastAction = React.forwardRef<
56 React.ElementRef<typeof ToastPrimitives.Action>,
57 React.ComponentPropsWithoutRef<typeof ToastPrimitives.Action>
58>(({ className, ...props }, ref) => (
59 <ToastPrimitives.Action
60 ref={ref}
61 className={cn(
62 "inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium transition-colors hover:bg-secondary focus:outline-none focus:ring-1 focus:ring-ring disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive",
63 className
64 )}
65 {...props}
66 />
67))
68ToastAction.displayName = ToastPrimitives.Action.displayName
69
70const ToastClose = React.forwardRef<
71 React.ElementRef<typeof ToastPrimitives.Close>,
72 React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>
73>(({ className, ...props }, ref) => (
74 <ToastPrimitives.Close
75 ref={ref}
76 className={cn(
77 "absolute right-1 top-1 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-1 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600",
78 className
79 )}
80 toast-close=""
81 {...props}
82 >
83 <Cross2Icon className="h-4 w-4" />
84 </ToastPrimitives.Close>
85))
86ToastClose.displayName = ToastPrimitives.Close.displayName
87
88const ToastTitle = React.forwardRef<
89 React.ElementRef<typeof ToastPrimitives.Title>,
90 React.ComponentPropsWithoutRef<typeof ToastPrimitives.Title>
91>(({ className, ...props }, ref) => (
92 <ToastPrimitives.Title
93 ref={ref}
94 className={cn("text-sm font-semibold [&+div]:text-xs", className)}
95 {...props}
96 />
97))
98ToastTitle.displayName = ToastPrimitives.Title.displayName
99
100const ToastDescription = React.forwardRef<
101 React.ElementRef<typeof ToastPrimitives.Description>,
102 React.ComponentPropsWithoutRef<typeof ToastPrimitives.Description>
103>(({ className, ...props }, ref) => (
104 <ToastPrimitives.Description
105 ref={ref}
106 className={cn("text-sm opacity-90", className)}
107 {...props}
108 />
109))
110ToastDescription.displayName = ToastPrimitives.Description.displayName
111
112type ToastProps = React.ComponentPropsWithoutRef<typeof Toast>
113
114type ToastActionElement = React.ReactElement<typeof ToastAction>
115
116export {
117 type ToastProps,
118 type ToastActionElement,
119 ToastProvider,
120 ToastViewport,
121 Toast,
122 ToastTitle,
123 ToastDescription,
124 ToastClose,
125 ToastAction,
126}