{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "toast",
  "type": "registry:ui",
  "title": "Toast",
  "description": "A customizable and responsive toast notification system...",
  "author": "Ahdeetai <https://aditya.is-cool.dev>",
  "registryDependencies": [],
  "dependencies": ["motion", "lucide-react", "class-variance-authority"],
  "files": [
    {
      "type": "registry:ui",
      "path": "components/ui/toast.tsx",
      "content": "'use client';\nimport React, { useState, useEffect, useCallback, useRef } from 'react';\nimport { X, CheckCircle, AlertCircle, Info } from 'lucide-react';\nimport { cva } from 'class-variance-authority';\nimport { motion, AnimatePresence } from 'motion/react';\n\ninterface ToastAction {\n  label: string;\n  onClick: () => void;\n}\n\ninterface ToastCancel {\n  label: string;\n  onClick: () => void;\n}\n\ntype EasingFunction = [number, number, number, number];\ntype EasingName =\n  | 'linear'\n  | 'easeIn'\n  | 'easeOut'\n  | 'easeInOut'\n  | 'circIn'\n  | 'circOut'\n  | 'circInOut'\n  | 'backIn'\n  | 'backOut'\n  | 'backInOut'\n  | 'anticipate';\n\ntype ToastPosition =\n  | 'top-right'\n  | 'top-left'\n  | 'bottom-right'\n  | 'bottom-left'\n  | 'top'\n  | 'bottom';\n\ninterface ToastProps {\n  id?: string;\n  title?: string;\n  description?: string;\n  children?: React.ReactNode;\n  variant?:\n    | 'default'\n    | 'success'\n    | 'destructive'\n    | 'warning'\n    | 'info'\n    | 'loading';\n  position?: ToastPosition;\n  duration?: number;\n  action?: React.ReactNode | ToastAction;\n  cancel?: ToastCancel;\n  onClose?: () => void;\n  stackIndex?: number;\n  isVisible?: boolean;\n  isStacked?: boolean;\n  isHovered?: boolean;\n  stackDirection?: 'up' | 'down';\n  isExiting?: boolean;\n  totalCount?: number;\n  className?: string;\n  unstyled?: boolean;\n  closeButton?: boolean;\n  animation?: {\n    enter?: {\n      duration?: number;\n      ease?: EasingName | EasingFunction;\n      type?: 'spring' | 'tween';\n      damping?: number;\n      stiffness?: number;\n    };\n    exit?: {\n      duration?: number;\n      ease?: EasingName | EasingFunction;\n    };\n  };\n}\n\ninterface ToastState extends ToastProps {\n  id: string;\n  timestamp: number;\n}\n\ninterface ToastOptions {\n  id?: string;\n  title?: string;\n  description?: string;\n  children?: React.ReactNode;\n  variant?:\n    | 'default'\n    | 'success'\n    | 'destructive'\n    | 'warning'\n    | 'info'\n    | 'loading';\n  position?: ToastPosition;\n  duration?: number;\n  action?: React.ReactNode | ToastAction;\n  cancel?: ToastCancel;\n  className?: string;\n  unstyled?: boolean;\n  closeButton?: boolean;\n  animation?: {\n    enter?: {\n      duration?: number;\n      ease?: EasingName | EasingFunction;\n      type?: 'spring' | 'tween';\n      damping?: number;\n      stiffness?: number;\n    };\n    exit?: {\n      duration?: number;\n      ease?: EasingName | EasingFunction;\n    };\n  };\n}\n\ntype ToastListener = (toasts: ToastState[]) => void;\n\nclass ToastManager {\n  private toasts: ToastState[] = [];\n  private listeners: Set<ToastListener> = new Set();\n\n  subscribe(listener: ToastListener) {\n    this.listeners.add(listener);\n    return () => this.listeners.delete(listener);\n  }\n\n  private notify() {\n    this.listeners.forEach((listener) => listener([...this.toasts]));\n  }\n\n  add(props: ToastProps) {\n    const id = props.id || Math.random().toString(36).substr(2, 9);\n    const existingIndex = this.toasts.findIndex((toast) => toast.id === id);\n\n    if (existingIndex !== -1) {\n      this.toasts[existingIndex] = {\n        ...this.toasts[existingIndex],\n        ...props,\n        id,\n      };\n      this.notify();\n      return id;\n    }\n\n    const newToast: ToastState = {\n      ...props,\n      id,\n      timestamp: Date.now(),\n    };\n\n    this.toasts = [newToast, ...this.toasts];\n\n    if (this.toasts.length > 10) {\n      this.toasts = this.toasts.slice(0, 10);\n    }\n\n    this.notify();\n    return id;\n  }\n\n  update(id: string, props: Partial<ToastProps>) {\n    const index = this.toasts.findIndex((toast) => toast.id === id);\n    if (index !== -1) {\n      this.toasts[index] = { ...this.toasts[index], ...props };\n      this.notify();\n    }\n  }\n\n  remove(id: string) {\n    this.toasts = this.toasts.filter((toast) => toast.id !== id);\n    this.notify();\n  }\n\n  clear() {\n    this.toasts = [];\n    this.notify();\n  }\n\n  getToasts() {\n    return [...this.toasts];\n  }\n}\n\nconst toastManager = new ToastManager();\n\nexport function toast(message: string, options?: ToastOptions): string;\nexport function toast(options: ToastOptions & { title: string }): string;\nexport function toast(\n  options: ToastOptions & { children: React.ReactNode },\n): string;\nexport function toast(\n  messageOrOptions:\n    | string\n    | (ToastOptions & ({ title: string } | { children: React.ReactNode })),\n  options?: ToastOptions,\n): string {\n  let toastProps: ToastOptions &\n    ({ title?: string } | { children?: React.ReactNode });\n\n  if (typeof messageOrOptions === 'string') {\n    toastProps = {\n      title: messageOrOptions,\n      ...options,\n    };\n  } else {\n    toastProps = messageOrOptions;\n  }\n\n  return toastManager.add(toastProps);\n}\n\ntoast.success = (message: string, options?: ToastOptions) =>\n  toast({ title: message, variant: 'success', ...options });\n\ntoast.error = (message: string, options?: ToastOptions) =>\n  toast({ title: message, variant: 'destructive', ...options });\n\ntoast.warning = (message: string, options?: ToastOptions) =>\n  toast({ title: message, variant: 'warning', ...options });\n\ntoast.info = (message: string, options?: ToastOptions) =>\n  toast({ title: message, variant: 'info', ...options });\n\ntoast.loading = (message: string, options?: ToastOptions) =>\n  toast({ title: message, variant: 'loading', duration: Infinity, ...options });\n\ntoast.custom = (children: React.ReactNode, options?: ToastOptions) =>\n  toast({ children, unstyled: true, closeButton: false, ...options });\n\ntoast.promise = <T,>(\n  promise: Promise<T>,\n  options: {\n    loading: string | { title?: string; children?: React.ReactNode };\n    success:\n      | string\n      | { title?: string; children?: React.ReactNode }\n      | ((data: T) => string | { title?: string; children?: React.ReactNode });\n    error:\n      | string\n      | { title?: string; children?: React.ReactNode }\n      | ((\n          error: Error,\n        ) => string | { title?: string; children?: React.ReactNode });\n  },\n  toastOptions?: ToastOptions,\n): Promise<T> => {\n  const loadingContent =\n    typeof options.loading === 'string'\n      ? { title: options.loading }\n      : options.loading;\n\n  const id = toast.loading(loadingContent.title || '', {\n    ...toastOptions,\n    ...loadingContent,\n  });\n\n  promise\n    .then((data) => {\n      const successContent =\n        typeof options.success === 'function'\n          ? options.success(data)\n          : options.success;\n\n      const content =\n        typeof successContent === 'string'\n          ? { title: successContent }\n          : successContent;\n\n      toastManager.update(id, {\n        variant: 'success',\n        duration: 5000,\n        ...content,\n      });\n    })\n    .catch((error: Error) => {\n      const errorContent =\n        typeof options.error === 'function'\n          ? options.error(error)\n          : options.error;\n\n      const content =\n        typeof errorContent === 'string'\n          ? { title: errorContent }\n          : errorContent;\n\n      toastManager.update(id, {\n        variant: 'destructive',\n        duration: 5000,\n        ...content,\n      });\n    });\n\n  return promise;\n};\n\ntoast.dismiss = (id?: string) => {\n  if (id) {\n    toastManager.remove(id);\n  } else {\n    toastManager.clear();\n  }\n};\n\nconst toastVariants = cva(\n  'toast-base fixed z-100 pointer-events-auto flex w-[calc(100%-2rem)] max-w-sm min-h-20 items-center justify-between space-x-4 rounded-lg p-4 pr-8 shadow-lg',\n  {\n    variants: {\n      variant: {\n        default: 'bg-background text-foreground border border-border',\n        success:\n          'bg-green-100 text-green-900 border-green-200 dark:bg-green-950 dark:text-green-50 dark:border-green-800',\n        destructive:\n          'bg-red-100 text-red-900 border-red-200 dark:bg-red-950 dark:text-red-50 dark:border-red-800',\n        warning:\n          'bg-yellow-100 text-yellow-900 border-yellow-200 dark:bg-yellow-950 dark:text-yellow-50 dark:border-yellow-800',\n        info: 'bg-blue-100 text-blue-900 border-blue-200 dark:bg-blue-950 dark:text-blue-50 dark:border-blue-800',\n        loading:\n          'bg-blue-100 text-blue-900 border-blue-200 dark:bg-blue-950 dark:text-blue-50 dark:border-blue-800',\n      },\n      position: {\n        'top-right': 'top-4 right-4',\n        'top-left': 'top-4 left-4',\n        'bottom-right': 'bottom-4 right-4',\n        'bottom-left': 'bottom-4 left-4',\n        top: 'top-4 left-1/2',\n        bottom: 'bottom-4 left-1/2',\n      },\n    },\n    defaultVariants: {\n      variant: 'default',\n      position: 'top-right',\n    },\n  },\n);\n\nconst ToastIcons = {\n  success: (\n    <CheckCircle className='h-5 w-5 text-green-600 dark:text-green-400 shrink-0' />\n  ),\n  destructive: (\n    <AlertCircle className='h-5 w-5 text-red-600 dark:text-red-400 shrink-0' />\n  ),\n  warning: (\n    <AlertCircle className='h-5 w-5 text-yellow-600 dark:text-yellow-400 shrink-0' />\n  ),\n  info: <Info className='h-5 w-5 text-blue-600 dark:text-blue-400 shrink-0' />,\n  loading: (\n    <div className='h-5 w-5 border-2 border-blue-600 border-t-transparent dark:border-blue-400 dark:border-t-transparent rounded-full animate-spin shrink-0' />\n  ),\n};\n\nconst ToastComponent: React.FC<ToastProps> = ({\n  id,\n  title,\n  description,\n  children,\n  variant = 'default',\n  position = 'top-right',\n  duration = 5000,\n  onClose,\n  action,\n  cancel,\n  stackIndex = 0,\n  isVisible = true,\n  isStacked = false,\n  isHovered = false,\n  stackDirection = 'down',\n  isExiting = false,\n  totalCount = 1,\n  className,\n  unstyled = false,\n  closeButton = true,\n  animation,\n}) => {\n  const [translateX, setTranslateX] = useState(0);\n  const [toastWidth, setToastWidth] = useState(320);\n  const [toastHeight, setToastHeight] = useState(88);\n  const toastRef = useRef<HTMLDivElement>(null);\n  const closeButtonRef = useRef<HTMLButtonElement>(null);\n  const startX = useRef(0);\n  const isDragging = useRef(false);\n  const isTouchAction = useRef(false);\n  const [isMobile, setIsMobile] = useState(false);\n\n  useEffect(() => {\n    if (toastRef.current) {\n      setToastWidth(toastRef.current.offsetWidth);\n      setToastHeight(toastRef.current.offsetHeight + 8);\n    }\n  }, [children, title, description]);\n\n  useEffect(() => {\n    const checkMobile = () => {\n      setIsMobile(window.innerWidth < 768);\n    };\n    checkMobile();\n    window.addEventListener('resize', checkMobile);\n    return () => window.removeEventListener('resize', checkMobile);\n  }, []);\n\n  const handleClose = useCallback(\n    (e?: React.UIEvent) => {\n      if (e) {\n        e.stopPropagation();\n        e.preventDefault();\n      }\n      onClose?.();\n    },\n    [onClose],\n  );\n\n  const handleTouchStart = useCallback(\n    (e: React.TouchEvent | React.MouseEvent) => {\n      if (e.target instanceof Element) {\n        if (\n          closeButtonRef.current?.contains(e.target) ||\n          e.target.closest('button[role=\"button\"]')\n        ) {\n          isTouchAction.current = true;\n          return;\n        }\n      }\n\n      e.stopPropagation();\n\n      const clientX =\n        'touches' in e ? e.touches[0].clientX : (e as React.MouseEvent).clientX;\n      startX.current = clientX;\n      isDragging.current = true;\n    },\n    [],\n  );\n\n  const handleTouchMove = useCallback(\n    (e: React.TouchEvent | React.MouseEvent) => {\n      if (isTouchAction.current || !isDragging.current || !toastRef.current)\n        return;\n\n      e.stopPropagation();\n      e.preventDefault();\n\n      const clientX =\n        'touches' in e ? e.touches[0].clientX : (e as React.MouseEvent).clientX;\n      const diff = clientX - startX.current;\n\n      if (isMobile) {\n        setTranslateX(diff);\n      } else {\n        if (position.includes('right') && diff > 0) {\n          setTranslateX(diff);\n        } else if (position.includes('left') && diff < 0) {\n          setTranslateX(diff);\n        }\n      }\n    },\n    [position, isMobile],\n  );\n\n  const handleTouchEnd = useCallback(\n    (e: React.TouchEvent | React.MouseEvent) => {\n      if (isTouchAction.current) {\n        isTouchAction.current = false;\n        return;\n      }\n\n      if (!isDragging.current || !toastRef.current) return;\n\n      e.stopPropagation();\n\n      const toastWidth = toastRef.current.offsetWidth;\n      const swipeThreshold = toastWidth * 0.3;\n\n      if (Math.abs(translateX) >= swipeThreshold) {\n        handleClose();\n      } else {\n        setTranslateX(0);\n      }\n\n      isDragging.current = false;\n    },\n    [translateX, handleClose],\n  );\n\n  useEffect(() => {\n    let timer: NodeJS.Timeout;\n    if (!isHovered && duration !== Infinity && duration > 0 && !isExiting) {\n      timer = setTimeout(() => {\n        handleClose();\n      }, duration);\n    }\n    return () => {\n      if (timer) clearTimeout(timer);\n    };\n  }, [duration, isHovered, handleClose, isExiting]);\n\n  useEffect(() => {\n    const currentRef = toastRef.current;\n    if (currentRef) {\n      const touchStartOptions = { passive: false };\n      currentRef.addEventListener(\n        'touchstart',\n        handleTouchStart as unknown as EventListener,\n        touchStartOptions,\n      );\n      window.addEventListener(\n        'touchmove',\n        handleTouchMove as unknown as EventListener,\n        { passive: false },\n      );\n      window.addEventListener(\n        'touchend',\n        handleTouchEnd as unknown as EventListener,\n      );\n\n      currentRef.addEventListener(\n        'mousedown',\n        handleTouchStart as unknown as EventListener,\n      );\n      window.addEventListener(\n        'mousemove',\n        handleTouchMove as unknown as EventListener,\n      );\n      window.addEventListener(\n        'mouseup',\n        handleTouchEnd as unknown as EventListener,\n      );\n    }\n\n    return () => {\n      if (currentRef) {\n        currentRef.removeEventListener(\n          'touchstart',\n          handleTouchStart as unknown as EventListener,\n        );\n        window.removeEventListener(\n          'touchmove',\n          handleTouchMove as unknown as EventListener,\n        );\n        window.removeEventListener(\n          'touchend',\n          handleTouchEnd as unknown as EventListener,\n        );\n\n        currentRef.removeEventListener(\n          'mousedown',\n          handleTouchStart as unknown as EventListener,\n        );\n        window.removeEventListener(\n          'mousemove',\n          handleTouchMove as unknown as EventListener,\n        );\n        window.removeEventListener(\n          'mouseup',\n          handleTouchEnd as unknown as EventListener,\n        );\n      }\n    };\n  }, [handleTouchStart, handleTouchMove, handleTouchEnd]);\n\n  if (!isVisible) return null;\n\n  const getTransform = () => {\n    const isCenter = position === 'top' || position === 'bottom';\n\n    if (isStacked && stackIndex > 0) {\n      const offset = stackIndex * 8;\n      const scale = Math.max(0.85, 1 - stackIndex * 0.05);\n      if (stackDirection === 'up') {\n        return isCenter\n          ? `translateX(-50%) translateY(-${offset}px) scale(${scale})`\n          : `translateX(${translateX}px) translateY(-${offset}px) scale(${scale})`;\n      } else {\n        return isCenter\n          ? `translateX(-50%) translateY(${offset}px) scale(${scale})`\n          : `translateX(${translateX}px) translateY(${offset}px) scale(${scale})`;\n      }\n    } else if (!isStacked && stackIndex > 0) {\n      const expandedOffset = stackIndex * toastHeight;\n      if (stackDirection === 'up') {\n        return isCenter\n          ? `translateX(-50%) translateY(-${expandedOffset}px)`\n          : `translateX(${translateX}px) translateY(-${expandedOffset}px)`;\n      } else {\n        return isCenter\n          ? `translateX(-50%) translateY(${expandedOffset}px)`\n          : `translateX(${translateX}px) translateY(${expandedOffset}px)`;\n      }\n    }\n\n    if (isCenter) {\n      return translateX !== 0\n        ? `translateX(calc(-50% + ${translateX}px))`\n        : `translateX(-50%)`;\n    }\n\n    return `translateX(${translateX}px)`;\n  };\n\n  const calculateOpacity = () => {\n    if (translateX !== 0) {\n      return Math.max(0.3, 1 - Math.abs(translateX) / toastWidth);\n    }\n    if (isStacked && stackIndex >= 3) {\n      return 0.4;\n    }\n    return 1;\n  };\n\n  const getZIndex = () => {\n    return 1100 - stackIndex;\n  };\n\n  const renderAction = () => {\n    if (!action) return null;\n\n    if (React.isValidElement(action)) {\n      const actionElement = action as React.ReactElement<{\n        onClick?: (e: React.MouseEvent) => void;\n      }>;\n      return (\n        <div\n          className='flex items-center gap-2 ml-auto shrink-0'\n          onClick={(e) => e.stopPropagation()}\n        >\n          {React.cloneElement(actionElement, {\n            onClick: (e: React.MouseEvent) => {\n              e.stopPropagation();\n              if (actionElement.props.onClick) {\n                actionElement.props.onClick(e);\n              }\n              handleClose();\n            },\n          })}\n        </div>\n      );\n    }\n\n    if (\n      typeof action === 'object' &&\n      action !== null &&\n      'label' in action &&\n      'onClick' in action\n    ) {\n      const actionObj = action as ToastAction;\n      return (\n        <div\n          className='flex items-center gap-2 shrink-0 w-full sm:w-auto sm:ml-auto'\n          onClick={(e) => e.stopPropagation()}\n        >\n          <button\n            onClick={(e) => {\n              e.stopPropagation();\n              actionObj.onClick();\n              handleClose();\n            }}\n            className='text-xs font-medium bg-primary text-primary-foreground hover:bg-primary/90 px-3 py-1 rounded transition-colors'\n          >\n            {actionObj.label}\n          </button>\n        </div>\n      );\n    }\n\n    return null;\n  };\n\n  const defaultEnterAnimation = {\n    duration: 0.3,\n    type: 'spring' as const,\n    damping: 30,\n    stiffness: 400,\n  };\n\n  const defaultExitAnimation = {\n    duration: 0.2,\n    ease: 'easeIn' as const,\n  };\n\n  const enterAnimation = animation?.enter || defaultEnterAnimation;\n  const exitAnimation = animation?.exit || defaultExitAnimation;\n\n  if (unstyled && children) {\n    const isCenter = position === 'top' || position === 'bottom';\n    return (\n      <motion.div\n        ref={toastRef}\n        initial={{\n          x: isCenter ? '-50%' : position.includes('right') ? 400 : -400,\n          y: position === 'top' ? -100 : position === 'bottom' ? 100 : 0,\n          opacity: 0,\n          scale: 0.9,\n        }}\n        animate={{\n          x: isCenter ? '-50%' : 0,\n          y: 0,\n          opacity: calculateOpacity(),\n          scale: stackIndex > 0 ? Math.max(0.85, 1 - stackIndex * 0.05) : 1,\n          transform: getTransform(),\n        }}\n        exit={{\n          x: isCenter ? '-50%' : position.includes('right') ? 400 : -400,\n          y: position === 'top' ? -100 : position === 'bottom' ? 100 : 0,\n          opacity: 0,\n          scale: 0.9,\n          transition: exitAnimation as never,\n        }}\n        transition={enterAnimation as never}\n        className={className}\n        style={{\n          zIndex: getZIndex(),\n          pointerEvents: 'auto',\n        }}\n      >\n        {children}\n        {closeButton && (\n          <button\n            ref={closeButtonRef}\n            onClick={handleClose}\n            className='absolute top-2 right-2 text-current/70 hover:text-current transition-colors'\n            aria-label='Close'\n          >\n            <X className='h-4 w-4' />\n          </button>\n        )}\n      </motion.div>\n    );\n  }\n\n  const isCenter = position === 'top' || position === 'bottom';\n\n  return (\n    <motion.div\n      ref={toastRef}\n      className={\n        unstyled\n          ? className\n          : `${toastVariants({ variant, position })} ${className || ''}`\n      }\n      initial={{\n        x: isCenter ? '-50%' : position.includes('right') ? 400 : -400,\n        y: position === 'top' ? -100 : position === 'bottom' ? 100 : 0,\n        opacity: 0,\n        scale: 0.9,\n      }}\n      animate={{\n        x: isCenter ? '-50%' : 0,\n        y: 0,\n        opacity: calculateOpacity(),\n        scale: stackIndex > 0 ? Math.max(0.85, 1 - stackIndex * 0.05) : 1,\n        transform: getTransform(),\n      }}\n      exit={{\n        x: isCenter ? '-50%' : position.includes('right') ? 400 : -400,\n        y: position === 'top' ? -100 : position === 'bottom' ? 100 : 0,\n        opacity: 0,\n        scale: 0.9,\n        transition: exitAnimation as never,\n      }}\n      transition={enterAnimation as never}\n      style={{\n        zIndex: getZIndex(),\n        pointerEvents: 'auto',\n      }}\n    >\n      <div className='flex flex-col sm:flex-row items-start gap-3 flex-1 min-w-0'>\n        {variant !== 'default' &&\n          ToastIcons[variant as keyof typeof ToastIcons]}\n        <div className='flex-1 min-w-0 w-full'>\n          {children ? (\n            <div className='flex-1'>{children}</div>\n          ) : (\n            <>\n              {title && (\n                <div className='font-semibold text-sm leading-tight mb-1'>\n                  {title}\n                </div>\n              )}\n              {description && (\n                <div className='text-xs opacity-90 leading-relaxed'>\n                  {description}\n                </div>\n              )}\n            </>\n          )}\n        </div>\n        {renderAction()}\n        {cancel && (\n          <div\n            className='flex items-center gap-2 shrink-0 w-full sm:w-auto sm:ml-2'\n            onClick={(e) => e.stopPropagation()}\n          >\n            <button\n              onClick={(e) => {\n                e.stopPropagation();\n                cancel.onClick();\n                handleClose();\n              }}\n              className='text-xs font-medium bg-muted text-muted-foreground hover:bg-muted/80 px-3 py-1 rounded transition-colors'\n            >\n              {cancel.label}\n            </button>\n          </div>\n        )}\n      </div>\n      {isStacked && stackIndex === 0 && totalCount > 3 && (\n        <div className='absolute -bottom-2 -right-2 bg-primary text-primary-foreground text-xs font-bold rounded-full w-6 h-6 flex items-center justify-center shadow-md'>\n          +{totalCount - 3}\n        </div>\n      )}\n      {closeButton && (\n        <button\n          ref={closeButtonRef}\n          onClick={handleClose}\n          className='absolute top-2 right-2 text-current/70 hover:text-current transition-colors'\n          aria-label='Close'\n        >\n          <X className='h-4 w-4' />\n        </button>\n      )}\n    </motion.div>\n  );\n};\n\ninterface ToastStackProps {\n  toasts: ToastState[];\n  position: string;\n  onRemoveToast: (id: string) => void;\n}\n\nconst ToastStack: React.FC<ToastStackProps> = ({\n  toasts,\n  position,\n  onRemoveToast,\n}) => {\n  const [isHovered, setIsHovered] = useState(false);\n  const [isTapped, setIsTapped] = useState(false);\n  const [isMobile, setIsMobile] = useState(false);\n  const hoverTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n\n  useEffect(() => {\n    const checkMobile = () => {\n      setIsMobile(window.innerWidth < 768);\n    };\n    checkMobile();\n    window.addEventListener('resize', checkMobile);\n    return () => {\n      window.removeEventListener('resize', checkMobile);\n    };\n  }, []);\n\n  const handleMouseEnter = useCallback(() => {\n    if (isMobile) return;\n    if (hoverTimeoutRef.current) {\n      clearTimeout(hoverTimeoutRef.current);\n      hoverTimeoutRef.current = null;\n    }\n    setIsHovered(true);\n  }, [isMobile]);\n\n  const handleMouseLeave = useCallback(\n    (e: React.MouseEvent) => {\n      if (isMobile) return;\n      const rect = e.currentTarget.getBoundingClientRect();\n      const { clientX, clientY } = e;\n\n      if (\n        clientX >= rect.left &&\n        clientX <= rect.right &&\n        clientY >= rect.top &&\n        clientY <= rect.bottom\n      ) {\n        return;\n      }\n\n      hoverTimeoutRef.current = setTimeout(() => {\n        setIsHovered(false);\n        hoverTimeoutRef.current = null;\n      }, 150);\n    },\n    [isMobile],\n  );\n\n  useEffect(() => {\n    return () => {\n      if (hoverTimeoutRef.current) {\n        clearTimeout(hoverTimeoutRef.current);\n      }\n    };\n  }, []);\n\n  const handleRemoveToast = useCallback(\n    (id: string) => {\n      const toastToRemove = toasts.find((t: ToastState) => t.id === id);\n      if (\n        toastToRemove &&\n        toasts.filter((t: ToastState) => t.position === toastToRemove.position)\n          .length === 1\n      ) {\n        setIsHovered(false);\n        setIsTapped(false);\n      }\n      onRemoveToast(id);\n    },\n    [toasts, onRemoveToast],\n  );\n\n  const handleStackInteraction = () => {\n    if (isMobile) {\n      setIsTapped(!isTapped);\n    }\n  };\n\n  const getVisibleToasts = () => {\n    const maxVisible = 3;\n    const shouldStack = toasts.length > 1;\n    const isExpanded = isMobile ? isTapped : isHovered;\n\n    if (shouldStack && !isExpanded) {\n      return toasts.slice(0, maxVisible);\n    }\n\n    return toasts.slice(0, maxVisible);\n  };\n\n  const visibleToasts = getVisibleToasts();\n\n  const getStackDirection = (pos: string) => {\n    return pos.includes('bottom') ? 'up' : 'down';\n  };\n\n  const stackDirection = getStackDirection(position);\n  const shouldStack = toasts.length > 1;\n  const isExpanded = isMobile ? isTapped : isHovered;\n\n  if (toasts.length === 0) return null;\n\n  return (\n    <div\n      className='fixed pointer-events-none z-1000'\n      onMouseEnter={handleMouseEnter}\n      onMouseLeave={handleMouseLeave}\n      onClick={handleStackInteraction}\n    >\n      <AnimatePresence mode='popLayout'>\n        {visibleToasts.map((toastProps, index) => (\n          <ToastComponent\n            key={toastProps.id}\n            {...toastProps}\n            stackIndex={index}\n            isStacked={shouldStack && !isExpanded}\n            isHovered={isHovered || isTapped}\n            stackDirection={stackDirection}\n            totalCount={toasts.length}\n            onClose={() => handleRemoveToast(toastProps.id)}\n          />\n        ))}\n      </AnimatePresence>\n    </div>\n  );\n};\n\nexport function ToastContainer() {\n  const [toasts, setToasts] = useState<ToastState[]>(toastManager.getToasts());\n  const [isMobile, setIsMobile] = useState(false);\n\n  useEffect(() => {\n    const checkMobile = () => {\n      setIsMobile(window.innerWidth < 768);\n    };\n    checkMobile();\n    window.addEventListener('resize', checkMobile);\n    return () => window.removeEventListener('resize', checkMobile);\n  }, []);\n\n  useEffect(() => {\n    const unsubscribe = toastManager.subscribe(setToasts);\n    return () => {\n      unsubscribe();\n    };\n  }, []);\n\n  const handleRemoveToast = useCallback((id: string) => {\n    toastManager.remove(id);\n  }, []);\n\n  const processedToasts = toasts.map((toast) => {\n    if (isMobile && toast.position !== 'top' && toast.position !== 'bottom') {\n      return {\n        ...toast,\n        position: 'top-right' as const,\n      };\n    }\n    return toast;\n  });\n\n  const toastsByPosition = processedToasts.reduce(\n    (acc, toast) => {\n      const position = toast.position || 'top-right';\n      if (!acc[position]) {\n        acc[position] = [];\n      }\n      acc[position].push(toast);\n      return acc;\n    },\n    {} as Record<string, ToastState[]>,\n  );\n\n  if (toasts.length === 0) return null;\n\n  return (\n    <>\n      {Object.entries(toastsByPosition).map(([position, positionToasts]) => (\n        <ToastStack\n          key={position}\n          toasts={positionToasts}\n          position={position}\n          onRemoveToast={handleRemoveToast}\n        />\n      ))}\n    </>\n  );\n}\n\nexport const useToast = () => {\n  return { toast };\n};\n\nexport const ToastProvider = ({ children }: { children: React.ReactNode }) => {\n  return (\n    <>\n      {children}\n      <ToastContainer />\n    </>\n  );\n};\n\nexport default ToastComponent;\n"
    }
  ]
}
