{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "toast",
  "title": "Toast",
  "description": "Toast component built on Base UI, styled with sc1m tokens.",
  "dependencies": [
    "@base-ui/react"
  ],
  "registryDependencies": [
    "https://sc1m.vercel.app/r/tokens.json",
    "https://sc1m.vercel.app/r/cn.json"
  ],
  "files": [
    {
      "path": "src/components/ui/toast/toast.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { Toast as BaseToast } from \"@base-ui/react/toast\";\nimport { cn } from \"@/lib/cn\";\n\nexport const ToastProvider = BaseToast.Provider;\nexport const useToastManager = BaseToast.useToastManager;\nexport const createToastManager = BaseToast.createToastManager;\n\n/**\n * Toast manager plus `nudge`: fire-with-a-stable-id for toasts that\n * should NOT stack. If the toast is already on screen, no new toast is\n * appended — the existing one is updated in place (Base UI's add() is\n * an upsert that also refreshes the auto-dismiss timer) and replays a\n * scale pulse (see toast-nudge in globals.css) as a visual nudge.\n */\nexport function useToast() {\n  const manager = BaseToast.useToastManager();\n\n  const nudge = React.useCallback(\n    (options: Parameters<typeof manager.add>[0] & { id: string }) => {\n      const exists = manager.toasts.some((t) => t.id === options.id);\n      manager.add(options);\n      if (exists) {\n        const el = document.querySelector<HTMLElement>(\n          `[data-toast-id=\"${options.id}\"]`,\n        );\n        if (el) {\n          // remove → reflow → re-add so the animation replays\n          el.classList.remove(\"toast-nudge\");\n          void el.offsetWidth;\n          el.classList.add(\"toast-nudge\");\n        }\n      }\n      return options.id;\n    },\n    [manager],\n  );\n\n  return { ...manager, nudge };\n}\n\n// Toasts position absolutely inside the viewport (the stack owns layout).\nexport function ToastViewport({\n  className,\n  ...props\n}: React.ComponentProps<typeof BaseToast.Viewport>) {\n  return (\n    <BaseToast.Portal>\n      <BaseToast.Viewport\n        className={cn(\"fixed right-4 bottom-4 z-50 w-80\", className)}\n        {...props}\n      />\n    </BaseToast.Portal>\n  );\n}\n\n/**\n * Sonner-style stacked toast (mechanics from Base UI's documented\n * recipe): older toasts peek out behind the frontmost one, scaled down\n * per --toast-index; hovering/focusing the viewport expands the stack\n * (data-expanded) using --toast-offset-y; swipe-to-dismiss exits toward\n * the swipe direction; toasts over the limit fade out (data-limited).\n */\nexport function Toast({\n  className,\n  children,\n  ...props\n}: React.ComponentProps<typeof BaseToast.Root>) {\n  return (\n    <BaseToast.Root\n      data-toast-id={props.toast.id}\n      className={cn(\n        \"[--gap:0.75rem] [--peek:0.75rem] [--scale:calc(max(0,1-(var(--toast-index)*0.1)))] [--shrink:calc(1-var(--scale))] [--height:var(--toast-frontmost-height,var(--toast-height))] [--offset-y:calc(var(--toast-offset-y)*-1+calc(var(--toast-index)*var(--gap)*-1)+var(--toast-swipe-movement-y))]\",\n        \"absolute right-0 bottom-0 left-auto z-[calc(1000-var(--toast-index))] w-full origin-bottom select-none\",\n        \"rounded-lg border border-line bg-surface-raised text-fg shadow-overlay\",\n        \"h-(--height) data-expanded:h-(--toast-height)\",\n        \"[transform:translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)-(var(--toast-index)*var(--peek))-(var(--shrink)*var(--height))))_scale(var(--scale))]\",\n        \"data-expanded:[transform:translateX(var(--toast-swipe-movement-x))_translateY(var(--offset-y))]\",\n        // invisible bridge over the gap so hover doesn't drop between toasts\n        \"after:absolute after:top-full after:left-0 after:h-[calc(var(--gap)+1px)] after:w-full after:content-['']\",\n        \"data-starting-style:[transform:translateY(150%)]\",\n        \"data-ending-style:opacity-0 data-limited:opacity-0\",\n        \"[&[data-ending-style]:not([data-limited]):not([data-swipe-direction])]:[transform:translateY(150%)]\",\n        \"data-ending-style:data-[swipe-direction=down]:[transform:translateY(calc(var(--toast-swipe-movement-y)+150%))]\",\n        \"data-ending-style:data-[swipe-direction=up]:[transform:translateY(calc(var(--toast-swipe-movement-y)-150%))]\",\n        \"data-ending-style:data-[swipe-direction=left]:[transform:translateX(calc(var(--toast-swipe-movement-x)-150%))_translateY(var(--offset-y))]\",\n        \"data-ending-style:data-[swipe-direction=right]:[transform:translateX(calc(var(--toast-swipe-movement-x)+150%))_translateY(var(--offset-y))]\",\n        \"[transition:transform_0.5s_var(--popup-ease),opacity_0.5s,height_0.15s] motion-reduce:transition-none\",\n        className,\n      )}\n      {...props}\n    >\n      {/* content behind the frontmost toast fades out until expanded */}\n      <BaseToast.Content className=\"relative overflow-hidden p-4 pr-8 transition-opacity duration-(--popup-open-dur) ease-(--popup-ease) data-behind:opacity-0 data-expanded:opacity-100 motion-reduce:transition-none\">\n        {children}\n      </BaseToast.Content>\n    </BaseToast.Root>\n  );\n}\n\nexport function ToastTitle({\n  className,\n  ...props\n}: React.ComponentProps<typeof BaseToast.Title>) {\n  return (\n    <BaseToast.Title\n      className={cn(\"text-sm font-medium text-fg\", className)}\n      {...props}\n    />\n  );\n}\n\nexport function ToastDescription({\n  className,\n  ...props\n}: React.ComponentProps<typeof BaseToast.Description>) {\n  return (\n    <BaseToast.Description\n      className={cn(\"mt-1 text-sm text-fg-muted\", className)}\n      {...props}\n    />\n  );\n}\n\nexport function ToastClose({\n  className,\n  ...props\n}: React.ComponentProps<typeof BaseToast.Close>) {\n  return (\n    <BaseToast.Close\n      className={cn(\n        \"absolute top-2 right-2 rounded-sm p-1 text-fg-subtle transition-colors duration-fast ease-out-quad hover:bg-surface hover:text-fg\",\n        \"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}