{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "sf-toast", "title": "SF Toast", "description": "System notification toast with GSAP slide entrance, Sonner engine, bottom-left positioning", "dependencies": [ "sonner", "gsap", "lucide-react" ], "registryDependencies": [], "files": [ { "path": "components/sf/sf-toast.tsx", "content": "\"use client\";\n\nimport { useRef, useEffect } from \"react\";\nimport { Toaster, toast } from \"sonner\";\nimport { gsap } from \"@/lib/gsap-core\";\nimport { cn } from \"@/lib/utils\";\nimport { X, Check, AlertTriangle, Info, AlertCircle } from \"lucide-react\";\n\n/* ── Intent border map ── */\nconst intentBorder: Record = {\n default: \"border-foreground\",\n success: \"border-success\",\n destructive: \"border-destructive\",\n warning: \"border-warning\",\n};\n\n/* ── SFToastContent ── */\ninterface SFToastContentProps {\n title: string;\n description?: string;\n icon?: React.ReactNode;\n intent?: \"default\" | \"success\" | \"destructive\" | \"warning\";\n onDismiss: () => void;\n}\n\nfunction SFToastContent({\n title,\n description,\n icon,\n intent = \"default\",\n onDismiss,\n}: SFToastContentProps) {\n const ref = useRef(null);\n\n useEffect(() => {\n if (!ref.current) return;\n\n // Reduced-motion guard — skip slide animation entirely\n if (window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches) return;\n\n const tween = gsap.fromTo(\n ref.current,\n { x: -40, opacity: 0 },\n { x: 0, opacity: 1, duration: 0.2, ease: \"power2.out\" }\n );\n\n return () => {\n tween.kill();\n };\n }, []);\n\n return (\n \n {icon && {icon}}\n
\n
\n {title}\n
\n {description && (\n
\n {description}\n
\n )}\n
\n \n \n \n \n );\n}\n\n/**\n * SFToaster — global toast container positioned bottom-left at z-100.\n * Place once in app/layout.tsx as a sibling to {children}.\n *\n * Uses Sonner in unstyled mode for full DU/TDR control.\n * Toast notifications slide in from the left via GSAP, respecting prefers-reduced-motion.\n *\n * @example\n * // In app/layout.tsx:\n * \n *\n * // Trigger from any client component:\n * import { sfToast } from \"@/components/sf\";\n * sfToast.success(\"OPERATION COMPLETE\");\n */\nfunction SFToaster() {\n return (\n \n );\n}\n\n/**\n * sfToast — imperative toast API.\n * Triggers custom Sonner toasts rendered with SFToastContent + GSAP slide.\n *\n * @example\n * sfToast.default(\"SYSTEM NOTICE\", { description: \"All systems nominal\" });\n * sfToast.success(\"SAVED\");\n * sfToast.error(\"CRITICAL FAILURE\");\n * sfToast.warning(\"LOW SIGNAL\");\n * sfToast.info(\"UPDATE AVAILABLE\");\n */\nconst sfToast = {\n default: (title: string, opts?: Omit) =>\n toast.custom((id) => (\n toast.dismiss(id)} {...opts} />\n )),\n success: (title: string, opts?: Omit) =>\n toast.custom((id) => (\n }\n intent=\"success\"\n onDismiss={() => toast.dismiss(id)}\n {...opts}\n />\n )),\n error: (title: string, opts?: Omit) =>\n toast.custom((id) => (\n }\n intent=\"destructive\"\n onDismiss={() => toast.dismiss(id)}\n {...opts}\n />\n )),\n warning: (title: string, opts?: Omit) =>\n toast.custom((id) => (\n }\n intent=\"warning\"\n onDismiss={() => toast.dismiss(id)}\n {...opts}\n />\n )),\n info: (title: string, opts?: Omit) =>\n toast.custom((id) => (\n }\n onDismiss={() => toast.dismiss(id)}\n {...opts}\n />\n )),\n};\n\nexport { SFToaster, sfToast };\n", "type": "registry:ui" } ], "meta": { "layer": "signal", "pattern": "A" }, "type": "registry:ui" }