/* Copyright 2026 Marimo. All rights reserved. */ import type { ComponentPropsWithoutRef, ReactElement, ReactNode } from "react"; import { useRef } from "react"; import { createPortal } from "react-dom"; import { CopyClipboardIcon } from "@/components/icons/copy-icon"; import { useToast } from "@/components/ui/use-toast"; import { StyleNamespace } from "@/theme/namespace"; import { cn } from "@/utils/cn"; import { withFullScreenAsRoot } from "./fullscreen"; import { Toast, ToastClose, ToastDescription, ToastProvider, ToastTitle, ToastViewport, } from "./toast"; export const Toaster = () => { const { toasts } = useToast(); return ( {toasts.map(({ id, title, description, action, variant, ...props }) => ( ))} ); }; const ToastViewportPortal = withFullScreenAsRoot( ({ container }: { container?: Element | DocumentFragment | null }) => createPortal( , container ?? document.body, ), ); type ToastItemProps = Omit< ComponentPropsWithoutRef, "title" | "children" > & { toastTitle?: ReactNode; toastDescription?: ReactNode; action?: ReactElement; }; const ToastItem = ({ toastTitle, toastDescription, action, variant, ...props }: ToastItemProps) => { const descriptionRef = useRef(null); // Show copy button for danger toasts without action, typically used for errors. const showCopy = Boolean(toastDescription) && !action && variant === "danger"; return ( {toastTitle && {toastTitle}} {toastDescription && ( {toastDescription} )} {action} {showCopy && ( descriptionRef.current?.innerText ?? (typeof toastDescription === "string" ? toastDescription : "") } /> )} ); };