{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "sonner",
  "title": "Sonner",
  "description": "Toaster for short confirmations: status types, surface or soft variant, optional countdown bar.",
  "dependencies": [
    "lucide-react",
    "sonner"
  ],
  "registryDependencies": [
    "@ikas/animated-check",
    "@ikas/button",
    "@ikas/spinner",
    "@ikas/status",
    "@ikas/utils"
  ],
  "files": [
    {
      "path": "registry/ui/sonner.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Toaster as Sonner, useSonner, type ToasterProps as SonnerProps } from \"sonner\"\nimport { AlertTriangleIcon, InfoIcon, OctagonAlertIcon } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { statusTint } from \"@/lib/status\"\nimport { buttonVariants } from \"@/components/ui/button\"\nimport { Spinner } from \"@/components/ui/spinner\"\nimport { AnimatedCheckIcon } from \"@/components/ikas/animated-check\"\n\ntype ToasterProps = SonnerProps & {\n  /**\n   * surface: popover card, the status in the icon (plus a thin leading accent for\n   * warning and error). soft: tinted with the status like a soft Banner; use sparingly.\n   */\n  variant?: \"surface\" | \"soft\"\n  /** 2px bar that counts down each toast's duration. Pauses on hover, hidden with reduced motion. */\n  progress?: boolean\n}\n\nconst DEFAULT_DURATION = 4000\n\n/** Follows the `dark` class on <html>, so toasts match the app without a theme provider. */\nfunction subscribeTheme(onChange: () => void) {\n  const observer = new MutationObserver(onChange)\n  observer.observe(document.documentElement, { attributes: true, attributeFilter: [\"class\"] })\n  return () => observer.disconnect()\n}\nconst getTheme = () => (document.documentElement.classList.contains(\"dark\") ? \"dark\" : \"light\")\nconst getServerTheme = () => \"light\" as const\n\n/**\n * Progress bar: a gradient on the content's ::after, which spans the whole toast.\n * Sonner keeps a toast's duration out of the DOM, so each toast gets its duration\n * through its place in the list (data-index), read from the toast store.\n */\nfunction useProgressCss(scope: string, enabled: boolean, props: ToasterProps) {\n  const { toasts } = useSonner()\n  if (!enabled) return null\n  const fallback = props.toastOptions?.duration ?? props.duration ?? DEFAULT_DURATION\n  const position = props.position ?? \"bottom-right\"\n  const indexes = new Map<string, number>()\n  const rules: string[] = []\n  for (const t of toasts) {\n    if (props.id ? t.toasterId !== props.id : t.toasterId) continue\n    const at = t.position ?? position\n    const index = indexes.get(at) ?? 0\n    indexes.set(at, index + 1)\n    const duration = t.duration ?? fallback\n    if (t.type === \"loading\" || !Number.isFinite(duration)) continue\n    const [y, x] = at.split(\"-\")\n    rules.push(\n      `.${scope}[data-y-position=\"${y}\"][data-x-position=\"${x}\"]>[data-index=\"${index}\"]:not([data-type=\"loading\"])>[data-content]::after{display:block;animation-duration:${duration}ms}`\n    )\n  }\n  return [\n    `.${scope} [data-content]::after{content:\"\";display:none;position:absolute;inset:0;border-radius:calc(var(--radius) * 1.4);pointer-events:none;background:linear-gradient(var(--s-icon),var(--s-icon)) left bottom / 0 2px no-repeat;animation:ikas-toast-progress 0ms linear forwards}`,\n    `.${scope}:hover [data-content]::after{animation-play-state:paused}`,\n    `@keyframes ikas-toast-progress{from{background-size:100% 2px}to{background-size:0 2px}}`,\n    `@media (prefers-reduced-motion:no-preference){${rules.join(\"\")}}`,\n  ].join(\"\\n\")\n}\n\n/**\n * Sonner, unstyled and dressed in ikas tokens with the same status recipe as\n * Banner (@/lib/status). Use it for confirmations that need no follow-up\n * (\"Kaydedildi\"); anything the store owner must act on belongs in a Banner.\n */\nfunction Toaster({ variant = \"surface\", progress = false, className, theme, toastOptions, ...props }: ToasterProps) {\n  const documentTheme = React.useSyncExternalStore(subscribeTheme, getTheme, getServerTheme)\n  const scope = `ikas-toaster-${React.useId().replace(/[^\\w-]/g, \"\")}`\n  const progressCss = useProgressCss(scope, progress, { ...props, toastOptions })\n  const soft = variant === \"soft\"\n  // Surface only: warning and error get a 3px accent on the leading edge.\n  const accent = soft ? undefined : \"[--t-accent:var(--s)]\"\n\n  return (\n    <>\n      {progressCss && <style>{progressCss}</style>}\n      <Sonner\n        theme={theme ?? documentTheme}\n        position=\"bottom-right\"\n        gap={10}\n        visibleToasts={3}\n        className={cn(\"toaster group\", scope, className)}\n        icons={{\n          success: (\n            <span className=\"flex size-4.5 items-center justify-center rounded-full bg-(--s-icon) text-(--s-fg)\">\n              <AnimatedCheckIcon className=\"size-3\" strokeWidth={3} />\n            </span>\n          ),\n          info: <InfoIcon className=\"size-4.5 text-(--s-icon)\" />,\n          warning: <AlertTriangleIcon className=\"size-4.5 text-(--s-icon)\" />,\n          error: <OctagonAlertIcon className=\"size-4.5 text-(--s-icon)\" />,\n          loading: <Spinner className=\"size-4 text-icon\" />,\n        }}\n        toastOptions={{\n          ...toastOptions,\n          unstyled: true,\n          classNames: {\n            toast: cn(\n              \"group/toast flex w-full items-start gap-3 rounded-xl py-3 pr-3 pl-3.5 text-sm sm:w-[360px]\",\n              soft\n                ? \"bg-(--s-subtle) text-(--s-title) shadow-[inset_0_0_0_1px_var(--s-border),0_12px_32px_-8px_var(--shade-3),0_4px_10px_-4px_var(--shade-2)]\"\n                : \"bg-popover text-popover-foreground shadow-[inset_3px_0_0_0_var(--t-accent,transparent),0_0_0_1px_var(--shade-border),0_12px_32px_-8px_var(--shade-3),0_4px_10px_-4px_var(--shade-2)]\",\n              // Plain toast(): no icon, keep the text aligned with the surface edge.\n              \"has-[[data-icon]:empty]:pl-4\",\n              // Collapsed stack: the toasts behind the front one show only their edge.\n              \"data-[expanded=false]:data-[front=false]:[&>*]:opacity-0\"\n            ),\n            default: statusTint.neutral,\n            loading: statusTint.neutral,\n            success: statusTint.success,\n            info: statusTint.info,\n            warning: cn(statusTint.warning, accent),\n            error: cn(statusTint.danger, accent),\n            icon: \"relative mt-px flex size-4.5 shrink-0 items-center justify-center [&:empty]:hidden\",\n            content: \"flex min-w-0 flex-1 flex-col gap-0.5 py-px\",\n            title: \"font-medium leading-5\",\n            // `!`: Sonner's dark theme sets its own description color with a stronger selector.\n            description: cn(\"text-[13px] leading-5\", soft ? \"text-(--s-body)!\" : \"text-muted-foreground!\"),\n            // Like Banner actions: a neutral outline on the card, a tinted raised surface on soft.\n            actionButton: soft\n              ? cn(\n                  buttonVariants({ variant: \"ghost\", size: \"xs\" }),\n                  \"ml-1 shrink-0 self-center bg-tint-surface shadow-[inset_0_0_0_1px_var(--s-border),0_1px_2px_0_var(--shade-1)] [--c-text:var(--s-title)] hover:bg-tint-surface-hover focus-visible:ring-(--s-icon)/50\"\n                )\n              : cn(buttonVariants({ variant: \"outline\", size: \"xs\" }), \"ml-1 shrink-0 self-center\"),\n            cancelButton: cn(\n              buttonVariants({ variant: \"ghost\", size: \"xs\" }),\n              \"shrink-0 self-center\",\n              soft ? \"[--c-subtle:var(--s-hover)] [--c-text:var(--s-body)]\" : \"text-muted-foreground\"\n            ),\n            closeButton:\n              \"absolute top-2 right-2 flex size-6 items-center justify-center rounded-md border-0! bg-transparent! text-icon! transition-colors hover:bg-(--s-hover)! hover:text-foreground! [&_svg]:size-3.5\",\n            ...toastOptions?.classNames,\n          },\n        }}\n        {...props}\n      />\n    </>\n  )\n}\n\nexport { Toaster, type ToasterProps }\n",
      "type": "registry:ui"
    }
  ],
  "docs": "https://builders.ikas.com/tr/docs/app-development/ui-kit/components/toast",
  "categories": [
    "primitives",
    "feedback"
  ],
  "type": "registry:ui"
}