mirror of
https://github.com/shadcn-ui/taxonomy
synced 2026-05-24 09:48:32 +00:00
87 lines
2.2 KiB
TypeScript
87 lines
2.2 KiB
TypeScript
"use client"
|
|
|
|
import * as React from "react"
|
|
import hotToast, { Toaster as HotToaster } from "react-hot-toast"
|
|
|
|
import { cn } from "@/lib/utils"
|
|
import { Icons } from "@/components/icons"
|
|
|
|
export const Toaster = HotToaster
|
|
|
|
interface ToastProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
visible: boolean
|
|
}
|
|
|
|
export function Toast({ visible, className, ...props }: ToastProps) {
|
|
return (
|
|
<div
|
|
className={cn(
|
|
"min-h-16 mb-2 flex w-[350px] flex-col items-start gap-1 rounded-md bg-white px-6 py-4 shadow-lg",
|
|
visible && "animate-in slide-in-from-bottom-5",
|
|
className
|
|
)}
|
|
{...props}
|
|
/>
|
|
)
|
|
}
|
|
|
|
interface ToastIconProps extends Partial<React.SVGProps<SVGSVGElement>> {
|
|
name: keyof typeof Icons
|
|
}
|
|
|
|
Toast.Icon = function ToastIcon({ name, className, ...props }: ToastIconProps) {
|
|
const Icon = Icons[name]
|
|
|
|
if (!Icon) {
|
|
return null
|
|
}
|
|
|
|
return (
|
|
<div className="flex h-20 w-20 items-center justify-center rounded-full bg-slate-100">
|
|
<Icon className={cn("h-10 w-10", className)} {...props} />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
interface ToastTitleProps extends React.HTMLAttributes<HTMLHeadingElement> {}
|
|
|
|
Toast.Title = function ToastTitle({ className, ...props }: ToastTitleProps) {
|
|
return <p className={cn("text-sm font-medium", className)} {...props} />
|
|
}
|
|
|
|
interface ToastDescriptionProps
|
|
extends React.HTMLAttributes<HTMLParagraphElement> {}
|
|
|
|
Toast.Description = function ToastDescription({
|
|
className,
|
|
...props
|
|
}: ToastDescriptionProps) {
|
|
return <p className={cn("text-sm opacity-80", className)} {...props} />
|
|
}
|
|
|
|
interface ToastOpts {
|
|
title?: string
|
|
message: string
|
|
type?: "success" | "error" | "default"
|
|
duration?: number
|
|
}
|
|
|
|
export function toast(opts: ToastOpts) {
|
|
const { title, message, type = "default", duration = 3000 } = opts
|
|
|
|
return hotToast.custom(
|
|
({ visible }) => (
|
|
<Toast
|
|
visible={visible}
|
|
className={cn({
|
|
"bg-red-600 text-white": type === "error",
|
|
"bg-black text-white": type === "success",
|
|
})}
|
|
>
|
|
<Toast.Title>{title}</Toast.Title>
|
|
{message && <Toast.Description>{message}</Toast.Description>}
|
|
</Toast>
|
|
),
|
|
{ duration }
|
|
)
|
|
}
|