{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "hover-card-tone",
  "title": "Card-tone hover",
  "description": "Styled hover: the Card-tone set. 5 decorative hover variations (PrimaryHoverCard, SuccessHoverCard, WarningHoverCard, DangerHoverCard, InfoHoverCard) on the ai2 token system, powered by framer-motion, reduced-motion aware and sized sm to xl. Part of the free styled layer.",
  "dependencies": [
    "motion@^12.42.2",
    "lucide-react@^1.23.0"
  ],
  "registryDependencies": [
    "@ai2/tokens"
  ],
  "files": [
    {
      "path": "registry/ai2/styled/hover-card-tone.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\"\nimport {\n  AlertOctagon,\n  AlertTriangle,\n  CheckCircle,\n  Info,\n  Sparkles,\n  type LucideIcon,\n} from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\n\n/* HoverCard Tone family: 5 semantically toned hover cards. Self-contained (no\n   radix, no portal) - a trigger + a softly toned card positioned below it, opened\n   on hover/focus. The opening uses framer-motion (fade + a slight rise + scale) and\n   is pinned by reduced-motion. Each card carries the -soft background of its own\n   tone + the on-plan color + its icon. Color comes ONLY from semantic tokens; since\n   primary has no -soft, its background is derived from the primary token with\n   color-mix. Size = card width. */\n\nexport type StyledSize = \"sm\" | \"md\" | \"lg\" | \"xl\"\n\nconst cardWidth: Record<StyledSize, string> = {\n  sm: \"w-56\",\n  md: \"w-64\",\n  lg: \"w-72\",\n  xl: \"w-80\",\n}\n\ntype Tone = \"primary\" | \"success\" | \"warning\" | \"danger\" | \"info\"\n\n/* Tone map: per tone a soft ground plus an on-plan colour plus the trigger colour plus the icon plus the default body text. Success, warning, danger and info use the real -soft tokens; primary has no -soft, so its ground and border are derived from the primary token through color-mix. */\nconst tones: Record<\n  Tone,\n  {\n    Icon: LucideIcon\n    title: string\n    surface: string\n    trigger: string\n    body: string\n  }\n> = {\n  primary: {\n    Icon: Sparkles,\n    title: \"Primary\",\n    surface:\n      \"text-primary [background-color:color-mix(in_oklab,var(--color-primary)_12%,transparent)] [border-color:color-mix(in_oklab,var(--color-primary)_28%,transparent)]\",\n    trigger: \"text-primary\",\n    body: \"The primary tone highlights the main action or the most important detail in a view.\",\n  },\n  success: {\n    Icon: CheckCircle,\n    title: \"Success\",\n    surface:\n      \"bg-success-soft text-success-soft-foreground [border-color:color-mix(in_oklab,var(--color-success)_28%,transparent)]\",\n    trigger: \"text-success-soft-foreground\",\n    body: \"The action completed successfully and everything is in a healthy state.\",\n  },\n  warning: {\n    Icon: AlertTriangle,\n    title: \"Warning\",\n    surface:\n      \"bg-warning-soft text-warning-soft-foreground [border-color:color-mix(in_oklab,var(--color-warning)_28%,transparent)]\",\n    trigger: \"text-warning-soft-foreground\",\n    body: \"Something needs your attention before you continue, though nothing has failed yet.\",\n  },\n  danger: {\n    Icon: AlertOctagon,\n    title: \"Danger\",\n    surface:\n      \"bg-danger-soft text-danger-soft-foreground [border-color:color-mix(in_oklab,var(--color-danger)_28%,transparent)]\",\n    trigger: \"text-danger-soft-foreground\",\n    body: \"A destructive or failing state that needs to be resolved before you move on.\",\n  },\n  info: {\n    Icon: Info,\n    title: \"Info\",\n    surface:\n      \"bg-info-soft text-info-soft-foreground [border-color:color-mix(in_oklab,var(--color-info)_28%,transparent)]\",\n    trigger: \"text-info-soft-foreground\",\n    body: \"A neutral, informational note that adds context without demanding an action.\",\n  },\n}\n\n/* Tetikleyici temeli: focus ring + ikon uyumu (lucide svg + remixicon i). */\nconst triggerBase =\n  \"inline-flex items-center gap-1.5 rounded-md font-medium underline-offset-4 outline-none hover:underline focus-visible:ring-[3px] focus-visible:ring-ring/50 [&_svg]:size-4 [&_svg]:shrink-0 [&_i]:text-base [&_i]:leading-none\"\n\ninterface Props {\n  size?: StyledSize\n  trigger?: React.ReactNode\n  children?: React.ReactNode\n  className?: string\n}\n\n/* Shared shell: a toned card that opens on hover and focus. AnimatePresence watches a single motion child; to avoid a horizontal-centring transform clash, x:-50% is applied through motion (instead of Tailwind's -translate-x-1/2). */\nfunction ToneHoverCard({\n  tone,\n  size = \"md\",\n  trigger,\n  children,\n  className,\n}: Props & { tone: Tone }) {\n  const reduce = useReducedMotion()\n  const [open, setOpen] = React.useState(false)\n  const t = tones[tone]\n  const Icon = t.Icon\n\n  const show = () => setOpen(true)\n  const hide = () => setOpen(false)\n\n  const fallback = (\n    <button type=\"button\" className={cn(triggerBase, t.trigger)}>\n      Hover me\n    </button>\n  )\n\n  return (\n    <span\n      data-slot=\"styled-hover-card\"\n      data-tone={tone}\n      className=\"relative inline-flex\"\n      onMouseEnter={show}\n      onMouseLeave={hide}\n      onFocus={show}\n      onBlur={hide}\n    >\n      {trigger ?? fallback}\n      <AnimatePresence>\n        {open ? (\n          <motion.span\n            role=\"dialog\"\n            data-slot=\"styled-hover-card-content\"\n            initial={\n              reduce\n                ? { opacity: 0, x: \"-50%\" }\n                : { opacity: 0, x: \"-50%\", y: 4, scale: 0.98 }\n            }\n            animate={\n              reduce\n                ? { opacity: 1, x: \"-50%\" }\n                : { opacity: 1, x: \"-50%\", y: 0, scale: 1 }\n            }\n            exit={\n              reduce\n                ? { opacity: 0, x: \"-50%\" }\n                : { opacity: 0, x: \"-50%\", y: 4, scale: 0.98 }\n            }\n            transition={\n              reduce ? { duration: 0 } : { type: \"spring\", stiffness: 320, damping: 26 }\n            }\n            className={cn(\n              \"absolute left-1/2 top-full z-20 mt-2 block origin-top rounded-xl border p-4 text-left shadow-lg [&_i]:text-base [&_i]:leading-none [&_svg]:size-4 [&_svg]:shrink-0\",\n              cardWidth[size],\n              t.surface,\n              className\n            )}\n          >\n            <span className=\"flex items-center gap-2 font-semibold\">\n              <Icon aria-hidden=\"true\" />\n              <span className=\"text-sm\">{t.title}</span>\n            </span>\n            <span className=\"mt-2 block text-sm opacity-90\">\n              {children ?? t.body}\n            </span>\n          </motion.span>\n        ) : null}\n      </AnimatePresence>\n    </span>\n  )\n}\n\n/* Primary: primary token'indan turetilmis yumusak zemin + Sparkles ikonu. */\nexport function PrimaryHoverCard(props: Props) {\n  return <ToneHoverCard tone=\"primary\" {...props} />\n}\n\n/* Success: success-soft zemin + CheckCircle ikonu. */\nexport function SuccessHoverCard(props: Props) {\n  return <ToneHoverCard tone=\"success\" {...props} />\n}\n\n/* Warning: warning-soft zemin + AlertTriangle ikonu. */\nexport function WarningHoverCard(props: Props) {\n  return <ToneHoverCard tone=\"warning\" {...props} />\n}\n\n/* Danger: danger-soft zemin + AlertOctagon ikonu. */\nexport function DangerHoverCard(props: Props) {\n  return <ToneHoverCard tone=\"danger\" {...props} />\n}\n\n/* Info: info-soft zemin + Info ikonu. */\nexport function InfoHoverCard(props: Props) {\n  return <ToneHoverCard tone=\"info\" {...props} />\n}\n",
      "type": "registry:component",
      "target": "components/ui/hover-card-tone.tsx"
    }
  ],
  "categories": [
    "styled",
    "hover"
  ],
  "type": "registry:component"
}