{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "toast",
  "title": "Toast",
  "description": "A toast provider built on Base UI.",
  "dependencies": [
    "@base-ui/react@^1.4.1"
  ],
  "registryDependencies": [
    "button",
    "utils"
  ],
  "files": [
    {
      "path": "registry/new-york-v4/ui/toast.tsx",
      "content": "\"use client\"\n\nimport type * as React from \"react\"\nimport { Toast } from \"@base-ui/react/toast\"\n\nimport { cn } from \"@/lib/utils\"\nimport { buttonVariants } from \"@/components/ui/button\"\nimport { IconPlaceholder } from \"@/components/icon-placeholder\"\n\ntype SwipeDirection = \"up\" | \"down\" | \"left\" | \"right\"\n\ntype ToastData = {\n  rootProps?: Omit<\n    React.ComponentProps<typeof Toast.Root>,\n    \"children\" | \"className\" | \"swipeDirection\" | \"toast\"\n  >\n  tooltipStyle?: boolean\n}\n\nfunction ToastIcon({ type }: { type?: string }) {\n  const className = cn(\n    \"size-4 shrink-0\",\n    type === \"loading\" && \"animate-spin opacity-80\",\n    type === \"error\" && \"text-destructive\",\n    type === \"info\" && \"text-info\",\n    type === \"success\" && \"text-success\",\n    type === \"warning\" && \"text-warning\"\n  )\n\n  switch (type) {\n    case \"error\":\n      return (\n        <IconPlaceholder\n          lucide=\"CircleAlertIcon\"\n          tabler=\"IconAlertCircle\"\n          hugeicons=\"Alert01Icon\"\n          phosphor=\"WarningCircleIcon\"\n          remixicon=\"RiErrorWarningLine\"\n          className={className}\n        />\n      )\n    case \"info\":\n      return (\n        <IconPlaceholder\n          lucide=\"InfoIcon\"\n          tabler=\"IconInfoCircle\"\n          hugeicons=\"InformationCircleIcon\"\n          phosphor=\"InfoIcon\"\n          remixicon=\"RiInformationLine\"\n          className={className}\n        />\n      )\n    case \"loading\":\n      return (\n        <IconPlaceholder\n          lucide=\"LoaderCircleIcon\"\n          tabler=\"IconLoader2\"\n          hugeicons=\"Loading03Icon\"\n          phosphor=\"SpinnerGapIcon\"\n          remixicon=\"RiLoaderLine\"\n          className={className}\n        />\n      )\n    case \"success\":\n      return (\n        <IconPlaceholder\n          lucide=\"CircleCheckIcon\"\n          tabler=\"IconCircleCheck\"\n          hugeicons=\"CheckmarkCircle01Icon\"\n          phosphor=\"CheckCircleIcon\"\n          remixicon=\"RiCheckboxCircleLine\"\n          className={className}\n        />\n      )\n    case \"warning\":\n      return (\n        <IconPlaceholder\n          lucide=\"TriangleAlertIcon\"\n          tabler=\"IconAlertTriangle\"\n          hugeicons=\"Alert01Icon\"\n          phosphor=\"WarningIcon\"\n          remixicon=\"RiAlertLine\"\n          className={className}\n        />\n      )\n    default:\n      return null\n  }\n}\n\nfunction ToastClose() {\n  return (\n    <Toast.Close\n      aria-label=\"Dismiss\"\n      className={buttonVariants({\n        className: \"-my-1 -mr-1 ml-1\",\n        size: \"icon-xs\",\n        variant: \"ghost\",\n      })}\n    >\n      <IconPlaceholder\n        lucide=\"XIcon\"\n        tabler=\"IconX\"\n        hugeicons=\"Cancel01Icon\"\n        phosphor=\"XIcon\"\n        remixicon=\"RiCloseLine\"\n      />\n    </Toast.Close>\n  )\n}\n\nfunction getSwipeDirection(position: ToastPosition): SwipeDirection[] {\n  const verticalDirection: SwipeDirection = position.startsWith(\"top\")\n    ? \"up\"\n    : \"down\"\n\n  if (position.includes(\"center\")) return [verticalDirection]\n  if (position.includes(\"left\")) return [\"left\", verticalDirection]\n  return [\"right\", verticalDirection]\n}\n\nfunction upsertReplayClassName(toast: {\n  type?: string\n  updateKey?: number\n}): string | undefined {\n  const key = toast.updateKey ?? 0\n  if (key <= 0) return undefined\n  const isEven = key % 2 === 0\n  if (toast.type === \"error\") {\n    return isEven ? \"animate-toast-error-even\" : \"animate-toast-error-odd\"\n  }\n  return isEven ? \"animate-toast-success-even\" : \"animate-toast-success-odd\"\n}\n\nfunction Toasts({\n  position,\n  portalProps,\n  viewportProps,\n}: {\n  position: ToastPosition\n  portalProps?: React.ComponentProps<typeof Toast.Portal>\n  viewportProps?: React.ComponentProps<typeof Toast.Viewport>\n}) {\n  const { toasts } = Toast.useToastManager()\n  const swipeDirection = getSwipeDirection(position)\n\n  return (\n    <Toast.Portal data-slot=\"toast-portal\" {...portalProps}>\n      <Toast.Viewport\n        {...viewportProps}\n        className={cn(\n          \"fixed z-60 mx-auto flex w-[calc(100%-var(--toast-inset)*2)] max-w-90 [--toast-inset:--spacing(4)] sm:[--toast-inset:--spacing(8)]\",\n          \"data-[position*=top]:top-(--toast-inset)\",\n          \"data-[position*=bottom]:bottom-(--toast-inset)\",\n          \"data-[position*=left]:left-(--toast-inset)\",\n          \"data-[position*=right]:right-(--toast-inset)\",\n          \"data-[position*=center]:left-1/2 data-[position*=center]:-translate-x-1/2\",\n          viewportProps?.className\n        )}\n        data-position={position}\n        data-slot=\"toast-viewport\"\n      >\n        {toasts.map((toast) => {\n          const toastData = toast.data as ToastData | undefined\n          return (\n            <Toast.Root\n              key={toast.id}\n              className={cn(\n                \"absolute z-[calc(9999-var(--toast-index))] h-(--toast-calc-height) w-full rounded-lg border bg-[color-mix(in_srgb,var(--popover),var(--color-black)_calc(1%*max(0,var(--toast-index,0))))] text-popover-foreground shadow-lg/5 select-none [transition:transform_.5s_cubic-bezier(.22,1,.36,1),opacity_.5s,height_.15s,background-color_.5s] not-dark:bg-clip-padding before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] before:shadow-[0_1px_--theme(--color-black/4%)] data-expanded:bg-popover dark:bg-[color-mix(in_srgb,var(--popover),var(--color-black)_calc(6%*max(0,var(--toast-index,0))))] dark:before:shadow-[0_-1px_--theme(--color-white/6%)] dark:data-expanded:bg-popover\",\n                \"data-[position*=right]:right-0 data-[position*=right]:left-auto\",\n                \"data-[position*=left]:right-auto data-[position*=left]:left-0\",\n                \"data-[position*=center]:right-0 data-[position*=center]:left-0\",\n                \"data-[position*=top]:top-0 data-[position*=top]:bottom-auto data-[position*=top]:origin-[50%_calc(50%-50%*min(var(--toast-index,0),1))]\",\n                \"data-[position*=bottom]:top-auto data-[position*=bottom]:bottom-0 data-[position*=bottom]:origin-[50%_calc(50%+50%*min(var(--toast-index,0),1))]\",\n                \"after:absolute after:left-0 after:h-[calc(var(--toast-gap)+1px)] after:w-full\",\n                \"data-[position*=top]:after:top-full\",\n                \"data-[position*=bottom]:after:bottom-full\",\n                \"[--toast-calc-height:var(--toast-frontmost-height,var(--toast-height))] [--toast-gap:--spacing(3)] [--toast-peek:--spacing(3)] [--toast-scale:calc(max(0,1-(var(--toast-index)*.1)))] [--toast-shrink:calc(1-var(--toast-scale))]\",\n                \"data-[position*=top]:[--toast-calc-offset-y:calc(var(--toast-offset-y)+var(--toast-index)*var(--toast-gap)+var(--toast-swipe-movement-y))]\",\n                \"data-[position*=bottom]:[--toast-calc-offset-y:calc(var(--toast-offset-y)*-1+var(--toast-index)*var(--toast-gap)*-1+var(--toast-swipe-movement-y))]\",\n                \"data-[position*=top]:transform-[translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)+(var(--toast-index)*var(--toast-peek))+(var(--toast-shrink)*var(--toast-calc-height))))_scale(var(--toast-scale))]\",\n                \"data-[position*=bottom]:transform-[translateX(var(--toast-swipe-movement-x))_translateY(calc(var(--toast-swipe-movement-y)-(var(--toast-index)*var(--toast-peek))-(var(--toast-shrink)*var(--toast-calc-height))))_scale(var(--toast-scale))]\",\n                \"data-limited:opacity-0\",\n                \"data-expanded:h-(--toast-height)\",\n                \"data-position:data-expanded:transform-[translateX(var(--toast-swipe-movement-x))_translateY(var(--toast-calc-offset-y))]\",\n                \"data-[position*=top]:data-starting-style:transform-[translateY(calc(-100%-var(--toast-inset)))]\",\n                \"data-[position*=bottom]:data-starting-style:transform-[translateY(calc(100%+var(--toast-inset)))]\",\n                \"data-ending-style:opacity-0\",\n                \"data-[position*=top]:data-ending-style:not-data-limited:not-data-swipe-direction:transform-[translateY(calc(-100%-var(--toast-inset)))]\",\n                \"data-[position*=bottom]:data-ending-style:not-data-limited:not-data-swipe-direction:transform-[translateY(calc(100%+var(--toast-inset)))]\",\n                \"data-ending-style:data-[swipe-direction=left]:transform-[translateX(calc(var(--toast-swipe-movement-x)-100%-var(--toast-inset)))_translateY(var(--toast-calc-offset-y))]\",\n                \"data-ending-style:data-[swipe-direction=right]:transform-[translateX(calc(var(--toast-swipe-movement-x)+100%+var(--toast-inset)))_translateY(var(--toast-calc-offset-y))]\",\n                \"data-ending-style:data-[swipe-direction=up]:transform-[translateY(calc(var(--toast-swipe-movement-y)-100%-var(--toast-inset)))]\",\n                \"data-ending-style:data-[swipe-direction=down]:transform-[translateY(calc(var(--toast-swipe-movement-y)+100%+var(--toast-inset)))]\",\n                \"data-expanded:data-ending-style:data-[swipe-direction=left]:transform-[translateX(calc(var(--toast-swipe-movement-x)-100%-var(--toast-inset)))_translateY(var(--toast-calc-offset-y))]\",\n                \"data-expanded:data-ending-style:data-[swipe-direction=right]:transform-[translateX(calc(var(--toast-swipe-movement-x)+100%+var(--toast-inset)))_translateY(var(--toast-calc-offset-y))]\",\n                \"data-expanded:data-ending-style:data-[swipe-direction=up]:transform-[translateY(calc(var(--toast-swipe-movement-y)-100%-var(--toast-inset)))]\",\n                \"data-expanded:data-ending-style:data-[swipe-direction=down]:transform-[translateY(calc(var(--toast-swipe-movement-y)+100%+var(--toast-inset)))]\",\n                upsertReplayClassName(toast)\n              )}\n              {...toastData?.rootProps}\n              data-position={position}\n              swipeDirection={swipeDirection}\n              toast={toast}\n            >\n              <Toast.Content className=\"pointer-events-auto flex items-center justify-between gap-1.5 overflow-hidden px-3.5 py-3 text-sm transition-opacity duration-250 data-behind:opacity-0 data-behind:not-data-expanded:pointer-events-none data-expanded:opacity-100\">\n                <div className=\"flex min-w-0 gap-2\">\n                  <ToastIcon type={toast.type} />\n                  <div className=\"flex min-w-0 flex-col gap-0.5\">\n                    <Toast.Title\n                      className=\"font-medium\"\n                      data-slot=\"toast-title\"\n                    />\n                    <Toast.Description\n                      className=\"text-muted-foreground\"\n                      data-slot=\"toast-description\"\n                    />\n                  </div>\n                </div>\n                <div className=\"flex shrink-0 items-center gap-1\">\n                  {toast.actionProps ? (\n                    <Toast.Action\n                      className={buttonVariants({ size: \"xs\" })}\n                      data-slot=\"toast-action\"\n                    >\n                      {toast.actionProps.children}\n                    </Toast.Action>\n                  ) : null}\n                  <ToastClose />\n                </div>\n              </Toast.Content>\n            </Toast.Root>\n          )\n        })}\n      </Toast.Viewport>\n    </Toast.Portal>\n  )\n}\n\nfunction AnchoredToasts({\n  portalProps,\n}: {\n  portalProps?: React.ComponentProps<typeof Toast.Portal>\n}) {\n  const { toasts } = Toast.useToastManager()\n  return (\n    <Toast.Portal data-slot=\"toast-portal-anchored\" {...portalProps}>\n      <Toast.Viewport\n        className=\"outline-none\"\n        data-slot=\"toast-viewport-anchored\"\n      >\n        {toasts.map((toast) => {\n          const toastData = toast.data as ToastData | undefined\n          const tooltipStyle = toastData?.tooltipStyle ?? false\n          const positionerProps = toast.positionerProps\n          if (!positionerProps?.anchor) return null\n\n          return (\n            <Toast.Positioner\n              key={toast.id}\n              className=\"z-50 max-w-[min(--spacing(64),var(--available-width))]\"\n              data-slot=\"toast-positioner\"\n              sideOffset={positionerProps.sideOffset ?? 4}\n              toast={toast}\n            >\n              <Toast.Root\n                className={cn(\n                  \"relative border bg-popover text-xs text-balance text-popover-foreground transition-[scale,opacity] not-dark:bg-clip-padding before:pointer-events-none before:absolute before:inset-0 before:shadow-[0_1px_--theme(--color-black/4%)] data-ending-style:scale-98 data-ending-style:opacity-0 data-starting-style:scale-98 data-starting-style:opacity-0 dark:before:shadow-[0_-1px_--theme(--color-white/6%)]\",\n                  tooltipStyle\n                    ? \"rounded-md shadow-md/5 before:rounded-[calc(var(--radius-md)-1px)]\"\n                    : \"rounded-lg shadow-lg/5 before:rounded-[calc(var(--radius-lg)-1px)]\",\n                  upsertReplayClassName(toast)\n                )}\n                {...toastData?.rootProps}\n                data-slot=\"toast-popup\"\n                toast={toast}\n              >\n                {tooltipStyle ? (\n                  <Toast.Content className=\"pointer-events-auto px-2 py-1\">\n                    <Toast.Title data-slot=\"toast-title\" />\n                  </Toast.Content>\n                ) : (\n                  <Toast.Content className=\"pointer-events-auto flex items-center justify-between gap-1.5 overflow-hidden px-3.5 py-3 text-sm\">\n                    <div className=\"flex min-w-0 gap-2\">\n                      <ToastIcon type={toast.type} />\n                      <div className=\"flex min-w-0 flex-col gap-0.5\">\n                        <Toast.Title\n                          className=\"font-medium\"\n                          data-slot=\"toast-title\"\n                        />\n                        <Toast.Description\n                          className=\"text-muted-foreground\"\n                          data-slot=\"toast-description\"\n                        />\n                      </div>\n                    </div>\n                    <div className=\"flex shrink-0 items-center gap-1\">\n                      {toast.actionProps ? (\n                        <Toast.Action\n                          className={buttonVariants({ size: \"xs\" })}\n                          data-slot=\"toast-action\"\n                        >\n                          {toast.actionProps.children}\n                        </Toast.Action>\n                      ) : null}\n                      <ToastClose />\n                    </div>\n                  </Toast.Content>\n                )}\n              </Toast.Root>\n            </Toast.Positioner>\n          )\n        })}\n      </Toast.Viewport>\n    </Toast.Portal>\n  )\n}\n\nexport const toastManager: ReturnType<typeof Toast.createToastManager> =\n  Toast.createToastManager()\n\nexport const anchoredToastManager: ReturnType<typeof Toast.createToastManager> =\n  Toast.createToastManager()\n\nexport type ToastPosition =\n  | \"top-left\"\n  | \"top-center\"\n  | \"top-right\"\n  | \"bottom-left\"\n  | \"bottom-center\"\n  | \"bottom-right\"\n\nexport interface ToastProviderProps extends Toast.Provider.Props {\n  position?: ToastPosition\n  portalProps?: React.ComponentProps<typeof Toast.Portal>\n  viewportProps?: React.ComponentProps<typeof Toast.Viewport>\n}\n\nexport function ToastProvider({\n  children,\n  position = \"bottom-right\",\n  portalProps,\n  viewportProps,\n  toastManager: manager = toastManager,\n  ...props\n}: ToastProviderProps) {\n  return (\n    <Toast.Provider toastManager={manager} {...props}>\n      {children}\n      <Toasts\n        portalProps={portalProps}\n        position={position}\n        viewportProps={viewportProps}\n      />\n    </Toast.Provider>\n  )\n}\n\nexport interface AnchoredToastProviderProps extends Toast.Provider.Props {\n  portalProps?: React.ComponentProps<typeof Toast.Portal>\n}\n\nexport function AnchoredToastProvider({\n  children,\n  portalProps,\n  toastManager: manager = anchoredToastManager,\n  ...props\n}: AnchoredToastProviderProps) {\n  return (\n    <Toast.Provider toastManager={manager} {...props}>\n      {children}\n      <AnchoredToasts portalProps={portalProps} />\n    </Toast.Provider>\n  )\n}\n\nexport { Toast as ToastPrimitive }\n",
      "type": "registry:ui",
      "target": "@ui/toast.tsx"
    }
  ],
  "type": "registry:ui"
}