{"name":"toast","type":"registry:ui","files":[{"path":"toast.tsx","type":"registry:ui","content":"\"use client\"\n\nimport * as React from \"react\"\nimport { Toast } from \"@base-ui/react/toast\"\nimport {\n  CircleAlert as CircleAlertIcon,\n  CircleCheck as CircleCheckIcon,\n  Info as InfoIcon,\n  LoaderCircle as LoaderCircleIcon,\n  TriangleAlert as TriangleAlertIcon,\n  X as XIcon,\n} from \"honestui/icons\"\n\nimport {\n  gooey,\n  Toaster as GooeyToaster,\n  type GooeyOptions,\n  type GooeyState,\n} from \"./toast-gooey\"\nimport { cn } from \"@/lib/utils\"\nimport { buttonVariants } from \"@/components/ui/button\"\n\nconst standardToastManager = Toast.createToastManager()\n\nconst TOAST_ICONS = {\n  loading: LoaderCircleIcon,\n  success: CircleCheckIcon,\n  error: CircleAlertIcon,\n  info: InfoIcon,\n  warning: TriangleAlertIcon,\n} as const\n\ntype ToastPosition =\n  | \"top-left\"\n  | \"top-center\"\n  | \"top-right\"\n  | \"bottom-left\"\n  | \"bottom-center\"\n  | \"bottom-right\"\n\ntype ToastVariant = \"default\" | \"standard\" | \"gooey\"\ntype StandardToastOptions = Parameters<typeof standardToastManager.add>[0]\ntype StandardToastUpdateOptions = Parameters<typeof standardToastManager.update>[1]\n\ninterface ToastOptions extends StandardToastOptions {\n  variant?: ToastVariant\n  position?: ToastPosition\n  state?: GooeyState\n  duration?: GooeyOptions[\"duration\"]\n  icon?: GooeyOptions[\"icon\"]\n  styles?: GooeyOptions[\"styles\"]\n  fill?: GooeyOptions[\"fill\"]\n  roundness?: GooeyOptions[\"roundness\"]\n  autopilot?: GooeyOptions[\"autopilot\"]\n  button?: GooeyOptions[\"button\"]\n}\n\ninterface ToastUpdateOptions extends StandardToastUpdateOptions {\n  variant?: ToastVariant\n  position?: ToastPosition\n  state?: GooeyState\n  duration?: GooeyOptions[\"duration\"]\n  icon?: GooeyOptions[\"icon\"]\n  styles?: GooeyOptions[\"styles\"]\n  fill?: GooeyOptions[\"fill\"]\n  roundness?: GooeyOptions[\"roundness\"]\n  autopilot?: GooeyOptions[\"autopilot\"]\n  button?: GooeyOptions[\"button\"]\n}\n\ninterface ToastPromiseOptions<Value> {\n  variant?: ToastVariant\n  position?: ToastPosition\n  loading: string | ToastOptions\n  success: string | ToastOptions | ((result: Value) => string | ToastOptions)\n  error: string | ToastOptions | ((error: unknown) => string | ToastOptions)\n}\n\ninterface ToastProviderProps extends Toast.Provider.Props {\n  position?: ToastPosition\n  gooeyPosition?: ToastPosition\n  gooeyOptions?: Partial<GooeyOptions>\n}\n\nfunction getGooeyState(type?: string, state?: GooeyState): GooeyState {\n  if (state) return state\n  if (\n    type === \"success\" ||\n    type === \"loading\" ||\n    type === \"error\" ||\n    type === \"warning\" ||\n    type === \"info\" ||\n    type === \"action\"\n  ) {\n    return type\n  }\n  return \"success\"\n}\n\nfunction getGooeyButton(options: ToastOptions | ToastUpdateOptions) {\n  if (options.button) return options.button\n\n  const children = options.actionProps?.children\n  const onClick = options.actionProps?.onClick\n  if (typeof children !== \"string\" || !onClick) return undefined\n\n  return {\n    title: children,\n    onClick: () => onClick({} as React.MouseEvent<HTMLButtonElement>),\n  }\n}\n\nfunction toGooeyOptions(options: ToastOptions | ToastUpdateOptions): GooeyOptions {\n  return {\n    title: typeof options.title === \"string\" ? options.title : undefined,\n    description: options.description,\n    position: options.position,\n    duration:\n      options.duration ??\n      (options.timeout === 0 ? null : options.timeout),\n    icon: options.icon,\n    styles: options.styles,\n    fill: options.fill,\n    roundness: options.roundness,\n    autopilot: options.autopilot,\n    button: getGooeyButton(options),\n  }\n}\n\nfunction addGooeyToast(options: ToastOptions) {\n  const state = getGooeyState(options.type, options.state)\n  const config = toGooeyOptions(options)\n\n  if (state === \"loading\") {\n    return (gooey.show as (opts: GooeyOptions & { state: GooeyState }) => string)(\n      { ...config, state }\n    )\n  }\n  return gooey[state](config)\n}\n\nfunction toStandardOptions(options: ToastOptions | ToastUpdateOptions) {\n  const standardOptions = { ...options }\n\n  delete standardOptions.variant\n  delete standardOptions.position\n  delete standardOptions.state\n  delete standardOptions.duration\n  delete standardOptions.icon\n  delete standardOptions.styles\n  delete standardOptions.fill\n  delete standardOptions.roundness\n  delete standardOptions.autopilot\n  delete standardOptions.button\n\n  return standardOptions\n}\n\nfunction resolvePromiseOption<Value>(\n  option: ToastPromiseOptions<Value>[\"success\"],\n  value: Value\n) {\n  return typeof option === \"function\" ? option(value) : option\n}\n\nfunction normalizePromiseOption(option: string | ToastOptions) {\n  return typeof option === \"string\" ? { title: option } : option\n}\n\nconst toastManager = {\n  add(options: ToastOptions) {\n    if (options.variant === \"gooey\") return addGooeyToast(options)\n    return standardToastManager.add(toStandardOptions(options))\n  },\n  close(id: string) {\n    standardToastManager.close(id)\n    gooey.dismiss(id)\n  },\n  update(id: string, options: ToastUpdateOptions) {\n    if (options.variant === \"gooey\") {\n      gooey.dismiss(id)\n      addGooeyToast(options as ToastOptions)\n      return\n    }\n\n    standardToastManager.update(id, toStandardOptions(options))\n  },\n  promise<Value>(\n    promiseValue: Promise<Value>,\n    options: ToastPromiseOptions<Value>\n  ) {\n    if (options.variant === \"gooey\") {\n      return gooey.promise(promiseValue, {\n        position: options.position,\n        loading: toGooeyOptions(normalizePromiseOption(options.loading)),\n        success: (result: Value) =>\n          toGooeyOptions(\n            normalizePromiseOption(resolvePromiseOption(options.success, result))\n          ),\n        error: (error: unknown) =>\n          toGooeyOptions(\n            normalizePromiseOption(resolvePromiseOption(options.error, error))\n          ),\n      })\n    }\n\n    return standardToastManager.promise(promiseValue, {\n      loading: toStandardOptions(normalizePromiseOption(options.loading)),\n      success: (result: Value) =>\n        toStandardOptions(\n          normalizePromiseOption(resolvePromiseOption(options.success, result))\n        ),\n      error: (error: unknown) =>\n        toStandardOptions(\n          normalizePromiseOption(resolvePromiseOption(options.error, error))\n        ),\n    })\n  },\n}\n\nfunction ToastProvider({\n  children,\n  position = \"bottom-right\",\n  gooeyPosition = \"top-right\",\n  gooeyOptions,\n  ...props\n}: ToastProviderProps) {\n  return (\n    <Toast.Provider toastManager={standardToastManager} {...props}>\n      {children}\n      <ToastList position={position} />\n      <GooeyToaster position={gooeyPosition} options={gooeyOptions} />\n    </Toast.Provider>\n  )\n}\n\nfunction ToastList({ position = \"bottom-right\" }: { position: ToastPosition }) {\n  const { toasts } = Toast.useToastManager()\n  const isTop = position.startsWith(\"top\")\n\n  return (\n    <Toast.Portal data-slot=\"toast-portal\">\n      <Toast.Viewport\n        className={cn(\n          \"fixed z-[var(--hui-z-index-toast)] w-[360px] max-w-[calc(100vw-var(--hui-space-10))] outline-none [--gap:var(--hui-space-4)]\",\n          \"data-[position=top-left]:top-[var(--hui-space-7)] data-[position=top-left]:left-[var(--hui-space-7)]\",\n          \"data-[position=top-center]:top-[var(--hui-space-7)] data-[position=top-center]:left-1/2 data-[position=top-center]:-translate-x-1/2\",\n          \"data-[position=top-right]:top-[var(--hui-space-7)] data-[position=top-right]:right-[var(--hui-space-7)]\",\n          \"data-[position=bottom-left]:bottom-[var(--hui-space-7)] data-[position=bottom-left]:left-[var(--hui-space-7)]\",\n          \"data-[position=bottom-center]:bottom-[var(--hui-space-7)] data-[position=bottom-center]:left-1/2 data-[position=bottom-center]:-translate-x-1/2\",\n          \"data-[position=bottom-right]:right-[var(--hui-space-7)] data-[position=bottom-right]:bottom-[var(--hui-space-7)]\"\n        )}\n        data-slot=\"toast-viewport\"\n        data-position={position}\n      >\n        {toasts.map((toast) => {\n          const Icon = toast.type\n            ? TOAST_ICONS[toast.type as keyof typeof TOAST_ICONS]\n            : null\n\n          return (\n            <Toast.Root\n              key={toast.id}\n              toast={toast}\n              data-position={position}\n              swipeDirection={\n                position.includes(\"center\")\n                  ? [isTop ? \"up\" : \"down\"]\n                  : position.includes(\"left\")\n                    ? [\"left\", isTop ? \"up\" : \"down\"]\n                    : [\"right\", isTop ? \"up\" : \"down\"]\n              }\n              className={cn(\n                \"absolute box-border h-[var(--height)] w-full cursor-default overflow-clip rounded-[var(--hui-radius-2)] border-[0.5px] border-[var(--hui-color-border-base-primary)] bg-[var(--hui-color-background-base-primary)] bg-clip-padding p-[var(--hui-space-3)] text-[var(--hui-color-foreground-base-primary)] shadow-[var(--hui-shadow-lifted)] select-none [--height:var(--toast-frontmost-height,var(--toast-height))] [--peek:var(--hui-space-4)] [--scale:calc(max(0,1-(var(--toast-index)*0.1)))] [--shrink:calc(1-var(--scale))] [transition:opacity_var(--hui-duration-slow)_var(--hui-ease-out)] z-[calc(var(--hui-z-index-toast)-var(--toast-index))] motion-safe:[transition:transform_var(--hui-duration-slow)_var(--hui-ease-out),opacity_var(--hui-duration-slow)_var(--hui-ease-out),height_var(--hui-duration-fast)_var(--hui-ease-out)] data-swiping:[transition:none]!\",\n                \"data-[position*=right]:right-0 data-[position*=right]:left-auto data-[position*=left]:right-auto data-[position*=left]:left-0 data-[position*=center]:right-0 data-[position*=center]:left-0\",\n                \"data-[position*=bottom]:top-auto data-[position*=bottom]:bottom-0 data-[position*=bottom]:origin-bottom data-[position*=bottom]:[--offset-y:calc(var(--toast-offset-y)*-1+(var(--toast-index)*var(--gap)*-1)+var(--toast-swipe-movement-y))] data-[position*=bottom]:[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-[position*=top]:top-0 data-[position*=top]:bottom-auto data-[position*=top]:origin-top data-[position*=top]:[--offset-y:calc(var(--toast-offset-y)+(var(--toast-index)*var(--gap))+var(--toast-swipe-movement-y))] data-[position*=top]:[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                \"after:absolute after:left-0 after:w-full after:content-[''] data-[position*=bottom]:after:bottom-full data-[position*=bottom]:after:h-[calc(var(--gap)+1px)] data-[position*=top]:after:top-full data-[position*=top]:after:h-[calc(var(--gap)+1px)]\",\n                \"data-expanded:h-[var(--toast-height)] data-expanded:[transform:translateX(var(--toast-swipe-movement-x))_translateY(var(--offset-y))]\",\n                \"data-starting-style:opacity-0 data-limited:opacity-0 data-ending-style:opacity-0\",\n                \"data-[position*=bottom]:data-starting-style:[transform:translateY(calc(100%+var(--hui-space-7)))] data-[position*=top]:data-starting-style:[transform:translateY(calc(-100%-var(--hui-space-7)))]\",\n                \"data-[position*=bottom]:data-ending-style:not-data-swipe-direction:[transform:translateY(calc(100%+var(--hui-space-7)))] data-[position*=top]:data-ending-style:not-data-swipe-direction:[transform:translateY(calc(-100%-var(--hui-space-7)))]\",\n                \"data-ending-style:data-[swipe-direction=up]:[transform:translateY(calc(var(--toast-swipe-movement-y)-150%))] data-ending-style:data-[swipe-direction=down]:[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))] data-ending-style:data-[swipe-direction=right]:[transform:translateX(calc(var(--toast-swipe-movement-x)+150%))_translateY(var(--offset-y))]\"\n              )}\n            >\n              <Toast.Content className=\"flex items-start gap-[var(--hui-space-3)] overflow-hidden [transition:opacity_var(--hui-duration-moderate)_var(--hui-ease-out)] data-behind:pointer-events-none data-behind:opacity-0 data-expanded:pointer-events-auto data-expanded:opacity-100\">\n                {Icon && (\n                  <div\n                    className=\"inline-flex min-h-[var(--hui-space-7)] w-[var(--hui-space-5)] shrink-0 items-center justify-center text-[var(--hui-color-foreground-base-secondary)] in-data-[type=error]:text-[var(--hui-color-foreground-danger-primary)] in-data-[type=info]:text-[var(--hui-color-foreground-accent-primary)] in-data-[type=success]:text-[var(--hui-color-foreground-success-primary)] in-data-[type=warning]:text-[var(--hui-color-foreground-attention-primary)] [&>svg]:size-[var(--hui-space-5)] [&>svg]:shrink-0 in-data-[type=loading]:[&>svg]:animate-spin\"\n                    data-slot=\"toast-icon\"\n                  >\n                    <Icon />\n                  </div>\n                )}\n\n                <div className=\"min-w-0 flex-1\" data-slot=\"toast-main\">\n                  <div className=\"flex min-h-[var(--hui-space-7)] items-center justify-between gap-[var(--hui-space-3)]\">\n                    <Toast.Title\n                      className=\"m-0 min-w-0 flex-1 text-[var(--hui-color-foreground-base-primary)] [font-size:var(--hui-font-size-regular)]! [font-weight:var(--hui-font-weight-medium)] [letter-spacing:var(--hui-letter-spacing-regular)] [line-height:var(--hui-line-height-regular)]! [text-wrap:wrap]!\"\n                      data-slot=\"toast-title\"\n                    />\n                    <div\n                      className=\"flex shrink-0 items-center gap-[var(--hui-space-1)]\"\n                      data-slot=\"toast-actions\"\n                    >\n                      {toast.actionProps && (\n                        <Toast.Action\n                          className={buttonVariants({\n                            variant: \"secondary\",\n                            size: \"xs\",\n                          })}\n                          data-slot=\"toast-action\"\n                        >\n                          {toast.actionProps.children}\n                        </Toast.Action>\n                      )}\n                      <Toast.Close\n                        aria-label=\"Dismiss notification\"\n                        className={buttonVariants({\n                          variant: \"link\",\n                          size: \"icon-sm\",\n                        })}\n                        data-slot=\"toast-close\"\n                      >\n                        <XIcon />\n                      </Toast.Close>\n                    </div>\n                  </div>\n                  <Toast.Description\n                    className=\"m-0 text-[var(--hui-color-foreground-base-primary)] [font-size:var(--hui-font-size-small)] [font-weight:var(--hui-font-weight-regular)] [letter-spacing:var(--hui-letter-spacing-small)] [line-height:var(--hui-line-height-small)]\"\n                    data-slot=\"toast-description\"\n                  />\n                </div>\n              </Toast.Content>\n            </Toast.Root>\n          )\n        })}\n      </Toast.Viewport>\n    </Toast.Portal>\n  )\n}\n\nexport { ToastProvider, type ToastPosition, type ToastVariant, toastManager }\n","target":"components/ui/toast.tsx"}],"dependencies":["@base-ui/react","honestui"],"registryDependencies":["https://www.honestui.com/r/button.json","https://www.honestui.com/r/toast-gooey.json"]}