{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "alert-action",
  "title": "Action alert",
  "description": "Styled alert: the Action set. 5 decorative alert variations (DismissAlert, LinkAlert, ButtonsAlert, InlineActionAlert, StackedAlert) 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/alert-action.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { ArrowRight, CircleAlert, CircleCheck, Info, TriangleAlert, X } from \"lucide-react\"\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\n\n/* Action alert family: 5 decorative alert surfaces. The shared idea is that the\n   alert carries a NEXT STEP - a dismiss control and/or action buttons.\n   Dismissing REALLY works: internal state plus an AnimatePresence exit\n   animation (only a fade under reduced-motion). The surface stays deliberately\n   calm (card plus a thin border) so attention goes to the action. Colour comes\n   ONLY from semantic tokens; alpha via color-mix or the tailwind opacity\n   modifier. Anatomy (Berkay's decision): the icon marks the TITLE ROW ONLY -\n   icon and title share line 1, the description starts BELOW the icon and takes\n   the full width; actions sit on their own row below the description. */\n\nexport type StyledSize = \"sm\" | \"md\" | \"lg\" | \"xl\"\n\nexport type StyledTone = \"info\" | \"success\" | \"warning\" | \"danger\"\n\nconst pad: Record<StyledSize, string> = {\n  sm: \"p-3 text-sm\",\n  md: \"p-4 text-sm\",\n  lg: \"p-4 text-base\",\n  xl: \"p-5 text-base\",\n}\n\n/* Grid columns change per variant, so there is NO grid-cols on the base. The\n   icon is a direct child, so the [&>svg] / [&>i] pair (lucide <svg> and\n   remixicon <i> compatibility) lives here. */\nconst base =\n  \"relative grid w-full items-start gap-x-2 gap-y-0.5 rounded-lg [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:translate-y-0.5 [&>i]:block [&>i]:size-4 [&>i]:shrink-0 [&>i]:translate-y-0.5 [&>i]:text-base [&>i]:leading-none\"\n\nconst cols2 = \"grid-cols-[calc(var(--spacing)*4)_1fr]\"\nconst cols3 = \"grid-cols-[calc(var(--spacing)*4)_1fr_auto]\"\n\n/* Tone -> varsayilan lucide ikon. */\nconst toneIcon: Record<StyledTone, React.ReactNode> = {\n  info: <Info />,\n  success: <CircleCheck />,\n  warning: <TriangleAlert />,\n  danger: <CircleAlert />,\n}\n\n/* Icon colour comes from the root; the [&>i] pair is required for remixicon\n   compatibility. */\nconst iconTone: Record<StyledTone, string> = {\n  info: \"[&>svg]:text-info [&>i]:text-info\",\n  success: \"[&>svg]:text-success [&>i]:text-success\",\n  warning: \"[&>svg]:text-warning-soft-foreground [&>i]:text-warning-soft-foreground\",\n  danger: \"[&>svg]:text-danger [&>i]:text-danger\",\n}\n\n/* A calm card surface plus a thin border tinted by tone. Identical across all\n   variants. */\nconst surfaceTone: Record<StyledTone, string> = {\n  info: \"border border-info/30 bg-card text-card-foreground shadow-xs\",\n  success: \"border border-success/30 bg-card text-card-foreground shadow-xs\",\n  warning: \"border border-warning/40 bg-card text-card-foreground shadow-xs\",\n  danger: \"border border-danger/30 bg-card text-card-foreground shadow-xs\",\n}\n\n/* Eylem butonu temeli: focus-visible ring zorunlu, ikon-uyum cifti dahil. */\nconst actionBtn =\n  \"inline-flex h-8 shrink-0 select-none items-center justify-center gap-1.5 whitespace-nowrap rounded-md px-3 text-sm font-medium outline-none transition-colors focus-visible:ring-[3px] focus-visible:ring-ring/50 [&_svg]:size-4 [&_svg]:shrink-0 [&_i]:text-base [&_i]:leading-none\"\n\nconst primaryBtn = cn(\n  actionBtn,\n  \"bg-primary text-primary-foreground hover:bg-[color-mix(in_oklab,var(--color-primary)_88%,var(--color-background))]\"\n)\n\nconst ghostBtn = cn(\n  actionBtn,\n  \"text-foreground hover:bg-[color-mix(in_oklab,var(--color-foreground)_7%,transparent)]\"\n)\n\n/* Metin baglantisi gibi okunan eylem. */\nconst linkBtn =\n  \"inline-flex items-center gap-1 rounded-sm text-sm font-medium underline underline-offset-4 outline-none transition-colors hover:no-underline focus-visible:ring-[3px] focus-visible:ring-ring/50 [&_svg]:size-4 [&_svg]:shrink-0 [&_i]:text-base [&_i]:leading-none\"\n\n/* The close button is 24px (size-6), so after:-inset-2 enlarges its touch\n   target. The button is absolutely positioned, so a containing block for after\n   already exists. */\nconst closeBtn =\n  \"absolute right-2 top-2 inline-flex size-6 items-center justify-center rounded-md text-muted-foreground outline-none transition-colors after:absolute after:-inset-2 hover:bg-[color-mix(in_oklab,var(--color-foreground)_7%,transparent)] hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50 [&_svg]:size-4 [&_svg]:shrink-0 [&_i]:text-base [&_i]:leading-none\"\n\ntype AlertProps = Omit<React.ComponentProps<\"div\">, \"title\"> & {\n  size?: StyledSize\n  tone?: StyledTone\n  title?: React.ReactNode\n  icon?: React.ReactNode\n}\n\n/* Shared shell: the column count, the description span, the action row and the\n   trailing node that goes into the title row all come from outside. */\nfunction Frame({\n  size,\n  tone,\n  title,\n  icon,\n  children,\n  className,\n  cols = cols2,\n  span = \"col-span-2\",\n  actions,\n  trailing,\n  ...props\n}: Omit<AlertProps, \"size\" | \"tone\"> & {\n  size: StyledSize\n  tone: StyledTone\n  cols?: string\n  span?: string\n  actions?: React.ReactNode\n  trailing?: React.ReactNode\n}) {\n  return (\n    <div\n      data-slot=\"styled-alert\"\n      data-tone={tone}\n      role=\"alert\"\n      className={cn(base, cols, pad[size], iconTone[tone], surfaceTone[tone], className)}\n      {...props}\n    >\n      {icon ?? toneIcon[tone]}\n      <div\n        data-slot=\"styled-alert-title\"\n        className=\"col-start-2 min-h-4 font-medium tracking-tight\"\n      >\n        {title}\n      </div>\n      {trailing}\n      <div\n        data-slot=\"styled-alert-description\"\n        className={cn(\"col-start-1 text-sm opacity-90 [&_p]:leading-relaxed\", span)}\n      >\n        {children}\n      </div>\n      {actions ? (\n        <div\n          data-slot=\"styled-alert-actions\"\n          className={cn(\"col-start-1 mt-3 flex items-center gap-2\", span)}\n        >\n          {actions}\n        </div>\n      ) : null}\n    </div>\n  )\n}\n\n/* Dismiss: a real close control in the top right. Internal state; once closed\n   the component renders nothing. The AnimatePresence exit falls back to a fade\n   only under reduced-motion (no height or transform). */\nexport function DismissAlert({\n  className,\n  size = \"md\",\n  tone = \"info\",\n  title = \"Heads up\",\n  children = \"A real dismiss control backed by internal state.\",\n  icon,\n  ...props\n}: AlertProps) {\n  const reduce = useReducedMotion()\n  const [open, setOpen] = React.useState(true)\n\n  return (\n    <AnimatePresence initial={false}>\n      {open ? (\n        <motion.div\n          initial={false}\n          exit={reduce ? { opacity: 0 } : { opacity: 0, height: 0, marginBottom: 0 }}\n          transition={{ duration: 0.2, ease: \"easeOut\" }}\n          className=\"overflow-hidden\"\n        >\n          <Frame\n            size={size}\n            tone={tone}\n            title={title}\n            icon={icon}\n            className={cn(\"pr-10\", className)}\n            trailing={\n              <button\n                type=\"button\"\n                aria-label=\"Dismiss\"\n                className={closeBtn}\n                onClick={() => setOpen(false)}\n              >\n                <X />\n              </button>\n            }\n            {...props}\n          >\n            {children}\n          </Frame>\n        </motion.div>\n      ) : null}\n    </AnimatePresence>\n  )\n}\n\n/* Link: aciklamanin altinda tek, hafif bir metin eylemi. En dusuk sesli eylem\n   varyanti. */\nexport function LinkAlert({\n  className,\n  size = \"md\",\n  tone = \"info\",\n  title = \"Heads up\",\n  children = \"A single quiet text action under the description.\",\n  icon,\n  ...props\n}: AlertProps) {\n  return (\n    <Frame\n      size={size}\n      tone={tone}\n      title={title}\n      icon={icon}\n      className={className}\n      actions={\n        <button type=\"button\" className={linkBtn}>\n          Learn more\n          <ArrowRight />\n        </button>\n      }\n      {...props}\n    >\n      {children}\n    </Frame>\n  )\n}\n\n/* Buttons: birincil + ikincil eylem cifti. Klasik onay/vazgec duzeni. */\nexport function ButtonsAlert({\n  className,\n  size = \"md\",\n  tone = \"info\",\n  title = \"Heads up\",\n  children = \"A primary and a secondary action under the description.\",\n  icon,\n  ...props\n}: AlertProps) {\n  return (\n    <Frame\n      size={size}\n      tone={tone}\n      title={title}\n      icon={icon}\n      className={className}\n      actions={\n        <>\n          <button type=\"button\" className={primaryBtn}>\n            Confirm\n          </button>\n          <button type=\"button\" className={ghostBtn}>\n            Cancel\n          </button>\n        </>\n      }\n      {...props}\n    >\n      {children}\n    </Frame>\n  )\n}\n\n/* InlineAction: eylem baslik satirinin sagina girer, aciklama yine ikonun\n   altindan tam genislikte akar. 3 sutunlu grid. */\nexport function InlineActionAlert({\n  className,\n  size = \"md\",\n  tone = \"info\",\n  title = \"Heads up\",\n  children = \"The action sits on the title row, not below the text.\",\n  icon,\n  ...props\n}: AlertProps) {\n  return (\n    <Frame\n      size={size}\n      tone={tone}\n      title={title}\n      icon={icon}\n      cols={cols3}\n      span=\"col-span-3\"\n      className={className}\n      trailing={\n        <button type=\"button\" className={cn(ghostBtn, \"col-start-3 -my-1 self-start\")}>\n          Review\n        </button>\n      }\n      {...props}\n    >\n      {children}\n    </Frame>\n  )\n}\n\n/* Stacked: full-width actions stacked on top of each other. Stays readable in\n   narrow columns and mobile layouts. */\nexport function StackedAlert({\n  className,\n  size = \"md\",\n  tone = \"info\",\n  title = \"Heads up\",\n  children = \"Full-width actions stacked for narrow columns.\",\n  icon,\n  ...props\n}: AlertProps) {\n  return (\n    <Frame\n      size={size}\n      tone={tone}\n      title={title}\n      icon={icon}\n      className={className}\n      actions={\n        <div className=\"flex w-full flex-col gap-2\">\n          <button type=\"button\" className={cn(primaryBtn, \"w-full\")}>\n            Update now\n          </button>\n          <button type=\"button\" className={cn(ghostBtn, \"w-full\")}>\n            Remind me later\n          </button>\n        </div>\n      }\n      {...props}\n    >\n      {children}\n    </Frame>\n  )\n}\n",
      "type": "registry:component",
      "target": "components/ui/alert-action.tsx"
    }
  ],
  "categories": [
    "styled",
    "alert"
  ],
  "type": "registry:component"
}