{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "notification-center-shadcnui",
  "type": "registry:component",
  "title": "Notification Center",
  "description": "Multi-variant notification stack with accessible announcements, actions, and motion states",
  "registryDependencies": [
    "button"
  ],
  "dependencies": [
    "framer-motion",
    "react"
  ],
  "files": [
    {
      "path": "@uitripled/react-shadcn/src/components/components/notifications/notification-center.tsx",
      "content": "\"use client\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { Card } from \"@/components/ui/card\";\nimport { cn } from \"@/lib/utils\";\nimport { AnimatePresence, motion, useReducedMotion } from \"framer-motion\";\nimport {\n  AlertCircle,\n  AlertTriangle,\n  CheckCircle,\n  ChevronDown,\n  Info,\n  LucideIcon,\n  X,\n} from \"lucide-react\";\nimport { useCallback, useState } from \"react\";\n\ntype NotificationType = \"success\" | \"error\" | \"warning\" | \"info\";\n\ntype NotificationConfig = {\n  title: string;\n  message: string;\n  description: string;\n  action: {\n    label: string;\n    onClick: () => void;\n  };\n  icon: LucideIcon;\n  toneClassName: string;\n};\n\ntype ActiveNotification = {\n  id: string;\n  type: NotificationType;\n};\n\nconst NOTIFICATION_CONFIGS: Record<NotificationType, NotificationConfig> = {\n  success: {\n    title: \"Success\",\n    message: \"Operation completed successfully\",\n    description:\n      \"Your changes have been saved to the database. All updates are now live.\",\n    action: {\n      label: \"View Details\",\n      onClick: () => console.log(\"View details\"),\n    },\n    icon: CheckCircle,\n    toneClassName: \"text-green-500\",\n  },\n  error: {\n    title: \"Error Occurred\",\n    message: \"Something went wrong\",\n    description:\n      \"Failed to process your request. Please try again or contact support if the issue persists.\",\n    action: { label: \"Retry\", onClick: () => console.log(\"Retry\") },\n    icon: AlertCircle,\n    toneClassName: \"text-red-500\",\n  },\n  warning: {\n    title: \"Warning\",\n    message: \"Please review this action\",\n    description:\n      \"This action may have unintended consequences. Review the details before proceeding.\",\n    action: { label: \"Learn More\", onClick: () => console.log(\"Learn more\") },\n    icon: AlertTriangle,\n    toneClassName: \"text-yellow-500\",\n  },\n  info: {\n    title: \"Information\",\n    message: \"New feature available\",\n    description:\n      \"Check out our new notification system with expandable details. Click to see more information.\",\n    action: { label: \"Explore\", onClick: () => console.log(\"Explore\") },\n    icon: Info,\n    toneClassName: \"text-blue-500\",\n  },\n};\n\nconst BUTTON_CONFIGS: Array<{ type: NotificationType; label: string }> = [\n  { type: \"success\", label: \"Success\" },\n  { type: \"error\", label: \"Error\" },\n  { type: \"warning\", label: \"Warning\" },\n  { type: \"info\", label: \"Info\" },\n];\n\nexport function NotificationCenter() {\n  const [notifications, setNotifications] = useState<ActiveNotification[]>([]);\n  const prefersReducedMotion = useReducedMotion() ?? false;\n\n  const addNotification = useCallback((type: NotificationType) => {\n    const id = Math.random().toString(36).slice(2, 9);\n    setNotifications((prev) => [...prev, { id, type }]);\n\n    window.setTimeout(() => {\n      setNotifications((prev) =>\n        prev.filter((notification) => notification.id !== id)\n      );\n    }, 8000);\n  }, []);\n\n  const removeNotification = useCallback((id: string) => {\n    setNotifications((prev) =>\n      prev.filter((notification) => notification.id !== id)\n    );\n  }, []);\n\n  return (\n    <div className=\"min-h-screen bg-background\">\n      <div\n        aria-live=\"polite\"\n        role=\"status\"\n        className=\"pointer-events-none fixed left-0 right-0 top-0 z-50 p-4 sm:p-6\"\n      >\n        <div className=\"pointer-events-auto mx-auto flex max-w-md flex-col gap-3\">\n          <AnimatePresence initial={false}>\n            {notifications.map((notification) => {\n              const config = NOTIFICATION_CONFIGS[notification.type];\n\n              return (\n                <NotificationBar\n                  key={notification.id}\n                  config={config}\n                  type={notification.type}\n                  notificationId={notification.id}\n                  onDismiss={() => removeNotification(notification.id)}\n                  prefersReducedMotion={prefersReducedMotion}\n                />\n              );\n            })}\n          </AnimatePresence>\n        </div>\n      </div>\n\n      <main className=\"flex min-h-screen items-center justify-center px-4\">\n        <div className=\"grid w-full grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-4\">\n          {BUTTON_CONFIGS.map(({ type, label }) => (\n            <motion.button\n              key={type}\n              type=\"button\"\n              onClick={() => addNotification(type)}\n              whileHover={{ scale: prefersReducedMotion ? 1 : 1.02 }}\n              whileTap={{ scale: prefersReducedMotion ? 1 : 0.98 }}\n              className=\"relative overflow-hidden rounded-2xl border border-border/50 bg-background/60 p-4 text-left transition-all duration-300 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:ring-offset-2 focus-visible:ring-offset-background sm:p-5\"\n            >\n              <div className=\"pointer-events-none absolute inset-0 bg-gradient-to-r from-foreground/[0.04] via-transparent to-transparent\" />\n              <div className=\"relative flex flex-col items-center gap-3 text-center\">\n                <ButtonIcon type={type} />\n                <span className=\"text-sm font-semibold text-foreground\">\n                  {label}\n                </span>\n              </div>\n            </motion.button>\n          ))}\n        </div>\n      </main>\n    </div>\n  );\n}\n\ntype NotificationBarProps = {\n  config: NotificationConfig;\n  type: NotificationType;\n  notificationId: string;\n  onDismiss: () => void;\n  prefersReducedMotion: boolean;\n};\n\nfunction NotificationBar({\n  config,\n  type,\n  notificationId,\n  onDismiss,\n  prefersReducedMotion,\n}: NotificationBarProps) {\n  const [isExpanded, setIsExpanded] = useState(false);\n  const {\n    action,\n    description,\n    icon: Icon,\n    message,\n    title,\n    toneClassName,\n  } = config;\n\n  return (\n    <motion.div\n      role=\"listitem\"\n      initial={{ opacity: 0, y: prefersReducedMotion ? 0 : -20 }}\n      animate={{ opacity: 1, y: 0 }}\n      exit={{ opacity: 0, scale: prefersReducedMotion ? 1 : 0.95 }}\n      transition={{ duration: prefersReducedMotion ? 0 : 0.3, ease: \"easeOut\" }}\n    >\n      <Card className=\"flex items-start gap-3 rounded-2xl border border-border/60 bg-background/80 p-4 backdrop-blur\">\n        <div\n          aria-hidden=\"true\"\n          className={cn(\n            \"flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-muted/80\",\n            toneClassName\n          )}\n        >\n          <Icon className=\"h-5 w-5\" />\n        </div>\n\n        <div className=\"flex flex-1 flex-col gap-2\">\n          <div className=\"flex items-start justify-between gap-3\">\n            <div className=\"flex-1\">\n              <h3 className=\"text-sm font-semibold text-foreground\">{title}</h3>\n              <p className=\"text-sm text-foreground/80\">{message}</p>\n            </div>\n            <motion.button\n              type=\"button\"\n              onClick={() => setIsExpanded((prev) => !prev)}\n              aria-expanded={isExpanded}\n              aria-controls={`notification-details-${notificationId}`}\n              whileHover={{ scale: prefersReducedMotion ? 1 : 1.05 }}\n              whileTap={{ scale: prefersReducedMotion ? 1 : 0.95 }}\n              className=\"flex h-8 w-8 items-center justify-center rounded-full border border-border/60 bg-background/40 text-foreground/60 transition-colors hover:text-foreground\"\n            >\n              <motion.span\n                animate={{ rotate: isExpanded ? 180 : 0 }}\n                transition={{\n                  duration: prefersReducedMotion ? 0 : 0.2,\n                  ease: \"easeOut\",\n                }}\n                className=\"flex\"\n              >\n                <ChevronDown className=\"h-4 w-4\" aria-hidden=\"true\" />\n              </motion.span>\n              <span className=\"sr-only\">\n                {isExpanded ? \"Hide details\" : \"Show details\"}\n              </span>\n            </motion.button>\n          </div>\n          <AnimatePresence initial={false}>\n            {isExpanded && (\n              <motion.div\n                key=\"details\"\n                id={`notification-details-${notificationId}`}\n                initial={{ height: 0, opacity: 0 }}\n                animate={{ height: \"auto\", opacity: 1 }}\n                exit={{ height: 0, opacity: 0 }}\n                transition={{\n                  duration: prefersReducedMotion ? 0 : 0.25,\n                  ease: \"easeOut\",\n                }}\n                className=\"overflow-hidden\"\n              >\n                <div className=\"mt-2 space-y-3 border-t border-border/40 pt-3 text-sm text-foreground/70\">\n                  <p>{description}</p>\n                  <div className=\"flex flex-wrap gap-2\">\n                    <Button\n                      type=\"button\"\n                      size=\"sm\"\n                      variant=\"outline\"\n                      onClick={action.onClick}\n                      className=\"rounded-full text-xs\"\n                    >\n                      {action.label}\n                    </Button>\n                    <Button\n                      type=\"button\"\n                      size=\"sm\"\n                      variant=\"ghost\"\n                      className=\"rounded-full text-xs\"\n                      onClick={() => {\n                        console.log(\"Remind me later\");\n                        onDismiss();\n                      }}\n                    >\n                      Remind me later\n                    </Button>\n                  </div>\n                </div>\n              </motion.div>\n            )}\n          </AnimatePresence>\n        </div>\n\n        <motion.button\n          type=\"button\"\n          onClick={onDismiss}\n          whileHover={{ scale: prefersReducedMotion ? 1 : 1.05 }}\n          whileTap={{ scale: prefersReducedMotion ? 1 : 0.95 }}\n          className=\"rounded-full p-1 text-foreground/60 transition-colors hover:text-foreground\"\n          aria-label={`Dismiss ${type} notification`}\n        >\n          <X className=\"h-4 w-4\" aria-hidden=\"true\" />\n        </motion.button>\n      </Card>\n    </motion.div>\n  );\n}\n\ntype ButtonIconProps = {\n  type: NotificationType;\n};\n\nfunction ButtonIcon({ type }: ButtonIconProps) {\n  const Icon = NOTIFICATION_CONFIGS[type].icon;\n  const prefersReducedMotion = useReducedMotion() ?? false;\n\n  return (\n    <motion.div\n      aria-hidden=\"true\"\n      whileHover={{ scale: prefersReducedMotion ? 1 : 1.1 }}\n      className=\"flex h-10 w-10 items-center justify-center rounded-full border border-border/60 bg-muted/60 text-foreground/70\"\n    >\n      <Icon className=\"h-5 w-5\" />\n    </motion.div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/uitripled/notification-center-shadcnui.tsx"
    }
  ]
}