{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "dependencies": [
    "@base-ui/react@1.8.0"
  ],
  "description": "A toast provider and a useLiquidToast hook for transient messages.",
  "docs": "Two steps after installing: import the copied stylesheet once at your app entry — it lands at `styles/liquefy-ui.css` — or `@import` it from your global CSS *before* `tailwindcss`, so Tailwind utilities keep winning over component styles. Then wrap the tree in `<LiquefyProvider>`, which is where every component reads its tokens from. Every copied file already carries its own 'use client' directive. Full documentation: https://liquefy-ui.com/#/docs/installation",
  "files": [
    {
      "content": "'use client'\n\nimport { Toast } from '@base-ui/react/toast'\nimport { createContext, useContext, useMemo, type ReactNode } from 'react'\nimport { DangerGlyph, InfoGlyph, SuccessGlyph, WarningGlyph, XGlyph } from '@/lib/internal-glyphs'\nimport type { LiquidAlertSeverity } from '@/components/ui/liquid-alert'\nimport { useLiquefyPortalContainer } from '@/lib/provider'\n\n// The old version kept its own array of toasts and dismissed each one from a\n// bare `setTimeout`. That timer ran whether or not anyone was reading: hovering\n// the stack, focusing a button inside it or tabbing away to another window all\n// left it counting down, so a message could vanish mid-sentence. Base UI owns\n// the queue now, and pauses it on hover, on focus and while the tab is hidden.\n\nexport type LiquidToastOptions = {\n  description?: ReactNode\n  duration?: number\n  severity?: LiquidAlertSeverity\n  title: ReactNode\n}\n\ntype ToastContextValue = {\n  dismiss: (id: string) => void\n  toast: (options: LiquidToastOptions) => string\n}\n\nconst ToastContext = createContext<ToastContextValue | null>(null)\n\nconst severityGlyphs = {\n  danger: <DangerGlyph size={17} />,\n  info: <InfoGlyph size={17} />,\n  success: <SuccessGlyph size={17} />,\n  warning: <WarningGlyph size={17} />,\n} as const\n\n/** How long a message sits there before it withdraws itself. */\nconst defaultDuration = 4200\n\nexport type LiquidToastProviderProps = {\n  children: ReactNode\n  placement?: 'bottom-right' | 'bottom-center' | 'top-right' | 'top-center'\n}\n\nconst severityOf = (type: string | undefined): LiquidAlertSeverity =>\n  type === 'success' || type === 'warning' || type === 'danger' ? type : 'info'\n\n/**\n * Bridges Base UI's manager to the hook this library already exported, so\n * `toast()` and `dismiss()` keep their shapes and the error thrown outside a\n * provider keeps naming the provider that is missing.\n */\nconst ToastBridge = ({ children }: { children: ReactNode }) => {\n  const manager = Toast.useToastManager()\n\n  const value = useMemo<ToastContextValue>(() => ({\n    dismiss: (id) => manager.close(id),\n    toast: ({ description, duration, severity = 'info', title }) => manager.add({\n      description,\n      // Base UI reads `0` as \"never dismiss on its own\", which is what this\n      // prop has always meant here too.\n      timeout: duration,\n      title,\n      type: severity,\n    }),\n  }), [manager])\n\n  return <ToastContext.Provider value={value}>{children}</ToastContext.Provider>\n}\n\nconst ToastList = () => {\n  const { toasts } = Toast.useToastManager()\n\n  return toasts.map((toast) => (\n    <Toast.Root className=\"lq-toast\" key={toast.id} toast={toast}>\n      <Toast.Content className=\"lq-toast__content\">\n        <span className=\"lq-toast__icon\">{severityGlyphs[severityOf(toast.type)]}</span>\n        <span className=\"lq-toast__copy\">\n          <Toast.Title render={<strong />} />\n          {toast.description && <Toast.Description render={<span />} />}\n        </span>\n        <Toast.Close aria-label=\"Dismiss\" className=\"lq-toast__close\">\n          <XGlyph size={12} />\n        </Toast.Close>\n      </Toast.Content>\n    </Toast.Root>\n  ))\n}\n\nexport const LiquidToastProvider = ({ children, placement = 'bottom-right' }: LiquidToastProviderProps) => {\n  // The theme tokens live on `.lq-provider`, so a viewport portaled to the body\n  // reads none of them: `--lq-solid-fill` resolves to nothing, the `color-mix`\n  // built on it is invalid, and the toast loses its fill and shadow entirely.\n  // The provider's own portal node is the fix Dialog, Drawer and Select already\n  // use — it is an unstyled div, so a fixed child still anchors to the screen.\n  // The body remains the fallback for a toast provider mounted on its own.\n  const portalContainer = useLiquefyPortalContainer()\n\n  return (\n    <Toast.Provider timeout={defaultDuration}>\n      <ToastBridge>{children}</ToastBridge>\n      <Toast.Portal container={portalContainer ?? undefined}>\n        <Toast.Viewport className=\"lq-toast-viewport\" data-placement={placement}>\n          <ToastList />\n        </Toast.Viewport>\n      </Toast.Portal>\n    </Toast.Provider>\n  )\n}\n\nexport const useLiquidToast = (): ToastContextValue => {\n  const context = useContext(ToastContext)\n  if (!context) throw new Error('useLiquidToast must be used within a LiquidToastProvider')\n  return context\n}\n",
      "path": "registry/liquid-toast.tsx",
      "type": "registry:ui"
    }
  ],
  "name": "liquid-toast",
  "registryDependencies": [
    "https://liquefy-ui.com/r/liquefy-ui.json",
    "https://liquefy-ui.com/r/internal-glyphs.json",
    "https://liquefy-ui.com/r/liquid-alert.json",
    "https://liquefy-ui.com/r/provider.json"
  ],
  "title": "LiquidToastProvider",
  "type": "registry:ui"
}
