{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "alert-dialog-illustration",
  "title": "Dialog-illustration alert",
  "description": "Styled alert: the Dialog-illustration set. 5 decorative alert variations (SpotlightAlert, BadgeAlert, CircleAlert, GradientAlert, BannerAlert) 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-dialog-illustration.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { AlertTriangle, Bell, CheckCircle, Info } from \"lucide-react\"\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\n\n/* Styled alert-dialog \"Illustration\" family: 5 decorative confirmation modals.\n   Same self-contained shell as the essentials alert-dialog-styled (no radix, no\n   portal): fixed backdrop + centered fixed panel; a backdrop click, Escape or\n   Cancel closes it; Confirm calls onConfirm first and then closes; the panel\n   takes focus on open; AnimatePresence handles enter/exit, and under reduced\n   motion it fades or switches instantly. The difference: a LARGE decorative\n   full-width visual region above the panel (spotlight, badge, rings, gradient\n   band, banner) - all built from tokens, no real image. Color comes ONLY from\n   tokens, via alpha/gradient/radial color-mix(in oklab ...). */\n\nexport type StyledSize = \"sm\" | \"md\" | \"lg\" | \"xl\"\n\nexport type StyledTone = \"info\" | \"success\" | \"warning\" | \"danger\" | \"brand\"\n\n/* Illustration bolgesinin hangi kompozisyonu cizecegini secen ayrimci. */\ntype IllustrationVariant = \"spotlight\" | \"badge\" | \"circle\" | \"gradient\" | \"banner\"\n\nconst panelWidth: Record<StyledSize, string> = {\n  sm: \"max-w-sm\",\n  md: \"max-w-md\",\n  lg: \"max-w-lg\",\n  xl: \"max-w-xl\",\n}\n\nconst bodyPad: Record<StyledSize, string> = {\n  sm: \"p-4\",\n  md: \"p-5\",\n  lg: \"p-6\",\n  xl: \"p-7\",\n}\n\n/* Illustration bolgesinin yuksekligi size ile buyur. */\nconst artHeight: Record<StyledSize, string> = {\n  sm: \"h-28\",\n  md: \"h-32\",\n  lg: \"h-36\",\n  xl: \"h-40\",\n}\n\n/* Confirm button tone mapping - the tone token drives it directly. */\nconst confirmTone: Record<StyledTone, string> = {\n  info: \"bg-info text-info-foreground hover:bg-info/90\",\n  success: \"bg-success text-success-foreground hover:bg-success/90\",\n  warning: \"bg-warning text-warning-foreground hover:bg-warning/90\",\n  danger: \"bg-danger text-danger-foreground hover:bg-danger/90\",\n  brand: \"bg-brand text-brand-foreground hover:bg-brand/90\",\n}\n\n/* Illustration ikon rengi tone token'ina baglanir. */\nconst artIconColor: Record<StyledTone, string> = {\n  info: \"text-info\",\n  success: \"text-success\",\n  warning: \"text-warning-soft-foreground\",\n  danger: \"text-danger\",\n  brand: \"text-brand\",\n}\n\nconst cancelBtn =\n  \"inline-flex h-9 items-center justify-center rounded-md border border-border bg-transparent px-4 text-sm font-medium text-foreground transition-colors hover:bg-secondary focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 [&_svg]:size-4 [&_svg]:shrink-0 [&_i]:text-base [&_i]:leading-none\"\n\nconst confirmBtn =\n  \"inline-flex h-9 items-center justify-center gap-1.5 rounded-md px-4 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 [&_svg]:size-4 [&_svg]:shrink-0 [&_i]:text-base [&_i]:leading-none\"\n\ntype StyledAlertPublicProps = {\n  size?: StyledSize\n  trigger?: React.ReactNode\n  title?: React.ReactNode\n  description?: React.ReactNode\n  confirmLabel?: string\n  cancelLabel?: string\n  onConfirm?: () => void\n  className?: string\n  open?: boolean\n  defaultOpen?: boolean\n  onOpenChange?: (o: boolean) => void\n}\n\ntype IllustratedAlertCoreProps = StyledAlertPublicProps & {\n  tone: StyledTone\n  variant: IllustrationVariant\n  icon: React.ReactNode\n}\n\n/* Tone token'indan olusan spotlight radial degeri (buyuk ustteki isik havuzu). */\nfunction spotlightBg(tone: StyledTone) {\n  const map: Record<StyledTone, string> = {\n    info: \"bg-[radial-gradient(120%_140%_at_50%_120%,color-mix(in_oklab,var(--color-info)_30%,transparent),transparent_70%)]\",\n    success:\n      \"bg-[radial-gradient(120%_140%_at_50%_120%,color-mix(in_oklab,var(--color-success)_30%,transparent),transparent_70%)]\",\n    warning:\n      \"bg-[radial-gradient(120%_140%_at_50%_120%,color-mix(in_oklab,var(--color-warning)_32%,transparent),transparent_70%)]\",\n    danger:\n      \"bg-[radial-gradient(120%_140%_at_50%_120%,color-mix(in_oklab,var(--color-danger)_28%,transparent),transparent_70%)]\",\n    brand:\n      \"bg-[radial-gradient(120%_140%_at_50%_120%,color-mix(in_oklab,var(--color-brand)_28%,transparent),transparent_70%)]\",\n  }\n  return map[tone]\n}\n\n/* Tone token'indan olusan gradient bant (soldan saga iki tonlu gecis). */\nfunction gradientBg(tone: StyledTone) {\n  const map: Record<StyledTone, string> = {\n    info: \"bg-[linear-gradient(120deg,color-mix(in_oklab,var(--color-info)_36%,transparent),color-mix(in_oklab,var(--color-info)_10%,transparent))]\",\n    success:\n      \"bg-[linear-gradient(120deg,color-mix(in_oklab,var(--color-success)_36%,transparent),color-mix(in_oklab,var(--color-success)_10%,transparent))]\",\n    warning:\n      \"bg-[linear-gradient(120deg,color-mix(in_oklab,var(--color-warning)_38%,transparent),color-mix(in_oklab,var(--color-warning)_10%,transparent))]\",\n    danger:\n      \"bg-[linear-gradient(120deg,color-mix(in_oklab,var(--color-danger)_34%,transparent),color-mix(in_oklab,var(--color-danger)_10%,transparent))]\",\n    brand:\n      \"bg-[linear-gradient(120deg,color-mix(in_oklab,var(--color-brand)_34%,transparent),color-mix(in_oklab,var(--color-brand)_10%,transparent))]\",\n  }\n  return map[tone]\n}\n\n/* Tone token'indan olusan yumusak dolgu (rozet / banner arka plani). */\nfunction softFill(tone: StyledTone) {\n  const map: Record<StyledTone, string> = {\n    info: \"bg-[color-mix(in_oklab,var(--color-info)_16%,transparent)]\",\n    success: \"bg-[color-mix(in_oklab,var(--color-success)_16%,transparent)]\",\n    warning: \"bg-[color-mix(in_oklab,var(--color-warning)_18%,transparent)]\",\n    danger: \"bg-[color-mix(in_oklab,var(--color-danger)_16%,transparent)]\",\n    brand: \"bg-[color-mix(in_oklab,var(--color-brand)_16%,transparent)]\",\n  }\n  return map[tone]\n}\n\n/* Tone token'indan olusan halka kenari (ic ice cemberler). */\nfunction ringBorder(tone: StyledTone) {\n  const map: Record<StyledTone, string> = {\n    info: \"border-[color-mix(in_oklab,var(--color-info)_35%,transparent)]\",\n    success: \"border-[color-mix(in_oklab,var(--color-success)_35%,transparent)]\",\n    warning: \"border-[color-mix(in_oklab,var(--color-warning)_38%,transparent)]\",\n    danger: \"border-[color-mix(in_oklab,var(--color-danger)_35%,transparent)]\",\n    brand: \"border-[color-mix(in_oklab,var(--color-brand)_35%,transparent)]\",\n  }\n  return map[tone]\n}\n\n/* Illustration area: a decorative top region per variant plus the tone icon in the middle. The motion gating lives here, because the reduce information comes from the core. */\nfunction Illustration({\n  variant,\n  tone,\n  icon,\n  size,\n  reduce,\n}: {\n  variant: IllustrationVariant\n  tone: StyledTone\n  icon: React.ReactNode\n  size: StyledSize\n  reduce: boolean\n}) {\n  const iconReveal = reduce\n    ? { initial: false as const, animate: { opacity: 1, scale: 1 } }\n    : {\n        initial: { opacity: 0, scale: 0.7 },\n        animate: { opacity: 1, scale: 1 },\n        transition: { duration: 0.28, ease: \"easeOut\" as const, delay: 0.05 },\n      }\n\n  const iconWrap = cn(\n    \"relative z-10 flex items-center justify-center [&_svg]:size-7 [&_svg]:shrink-0 [&_i]:text-3xl [&_i]:leading-none\",\n    artIconColor[tone]\n  )\n\n  return (\n    <div\n      data-slot=\"styled-alert-dialog-illustration\"\n      className={cn(\n        \"relative flex w-full items-center justify-center overflow-hidden border-b border-border\",\n        artHeight[size]\n      )}\n    >\n      {variant === \"spotlight\" ? (\n        <>\n          <div className={cn(\"absolute inset-0\", spotlightBg(tone))} />\n          <motion.span\n            className={cn(\n              \"flex size-14 items-center justify-center rounded-full border border-border bg-popover shadow-sm\",\n              iconWrap\n            )}\n            {...iconReveal}\n          >\n            {icon}\n          </motion.span>\n        </>\n      ) : null}\n\n      {variant === \"badge\" ? (\n        <motion.span\n          className={cn(\n            \"flex size-20 items-center justify-center rounded-full\",\n            softFill(tone),\n            iconWrap\n          )}\n          {...iconReveal}\n        >\n          {icon}\n        </motion.span>\n      ) : null}\n\n      {variant === \"circle\" ? (\n        <div className=\"relative flex items-center justify-center\">\n          <span\n            className={cn(\n              \"absolute size-24 rounded-full border\",\n              ringBorder(tone)\n            )}\n          />\n          <span\n            className={cn(\n              \"absolute size-16 rounded-full border\",\n              ringBorder(tone)\n            )}\n          />\n          <motion.span className={iconWrap} {...iconReveal}>\n            {icon}\n          </motion.span>\n        </div>\n      ) : null}\n\n      {variant === \"gradient\" ? (\n        <>\n          <div className={cn(\"absolute inset-0\", gradientBg(tone))} />\n          <motion.span\n            className={cn(\n              \"flex size-14 items-center justify-center rounded-2xl border border-border bg-popover shadow-sm\",\n              iconWrap\n            )}\n            {...iconReveal}\n          >\n            {icon}\n          </motion.span>\n        </>\n      ) : null}\n\n      {variant === \"banner\" ? (\n        <>\n          <div className={cn(\"absolute inset-0\", softFill(tone))} />\n          <div\n            className={cn(\n              \"absolute inset-x-0 top-0 h-1.5\",\n              confirmTone[tone].split(\" \")[0]\n            )}\n          />\n          <motion.span className={iconWrap} {...iconReveal}>\n            {icon}\n          </motion.span>\n        </>\n      ) : null}\n    </div>\n  )\n}\n\n/* Shared modal core: state management, backdrop, panel, escape, focus, motion. Identical to Essentials; it additionally renders an Illustration area on top. */\nfunction IllustratedAlertDialog({\n  size = \"md\",\n  trigger,\n  title,\n  description,\n  confirmLabel = \"Confirm\",\n  cancelLabel = \"Cancel\",\n  onConfirm,\n  className,\n  open,\n  defaultOpen,\n  onOpenChange,\n  tone,\n  variant,\n  icon,\n}: IllustratedAlertCoreProps) {\n  const reduce = useReducedMotion() ?? false\n  const isControlled = open !== undefined\n  const [internalOpen, setInternalOpen] = React.useState(defaultOpen ?? false)\n  const actualOpen = isControlled ? open : internalOpen\n  const panelRef = React.useRef<HTMLDivElement>(null)\n\n  const setOpen = React.useCallback(\n    (next: boolean) => {\n      if (!isControlled) setInternalOpen(next)\n      onOpenChange?.(next)\n    },\n    [isControlled, onOpenChange]\n  )\n\n  React.useEffect(() => {\n    if (!actualOpen) return\n    const onKey = (e: KeyboardEvent) => {\n      if (e.key === \"Escape\") setOpen(false)\n    }\n    document.addEventListener(\"keydown\", onKey)\n    const raf = window.requestAnimationFrame(() => panelRef.current?.focus())\n    return () => {\n      document.removeEventListener(\"keydown\", onKey)\n      window.cancelAnimationFrame(raf)\n    }\n  }, [actualOpen, setOpen])\n\n  const handleConfirm = () => {\n    onConfirm?.()\n    setOpen(false)\n  }\n\n  return (\n    <span data-slot=\"styled-alert-dialog\" className=\"contents\">\n      {/* ARIA durumu tetikleyicinin KENDISINDE. Once yoktu: ekran okuyucu\n\n          kullanicisi butonun bir dialog actigini ve acik olup olmadigini\n\n          HIC bilmiyordu. Canli AX taramasiyla bulundu (grep gostermemisti). */}\n\n      <span data-slot=\"styled-alert-dialog-trigger\" className=\"inline-flex\">\n\n        {React.isValidElement<React.ButtonHTMLAttributes<HTMLButtonElement>>(trigger) ? (\n\n          React.cloneElement(trigger, {\n\n            \"aria-haspopup\": \"dialog\",\n\n            \"aria-expanded\": actualOpen,\n\n            onClick: (event: React.MouseEvent<HTMLButtonElement>) => {\n\n              trigger.props.onClick?.(event)\n\n              setOpen(true)\n\n            },\n\n          })\n\n        ) : (\n\n          <button\n\n            type=\"button\"\n\n            aria-haspopup=\"dialog\"\n\n            aria-expanded={actualOpen}\n\n            onClick={() => setOpen(true)}\n\n            className=\"inline-flex h-9 items-center justify-center rounded-md border border-border bg-secondary px-4 text-sm font-medium text-secondary-foreground transition-colors hover:bg-secondary/80 focus-visible:outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50\"\n\n          >\n\n            {trigger ?? \"Open\"}\n\n          </button>\n\n        )}\n\n      </span>\n\n      <AnimatePresence>\n        {actualOpen ? (\n          <>\n            <motion.div\n              data-slot=\"styled-alert-dialog-backdrop\"\n              className=\"fixed inset-0 z-50 bg-[color-mix(in_oklab,var(--color-foreground)_45%,transparent)] supports-[backdrop-filter]:backdrop-blur-sm\"\n              onClick={() => setOpen(false)}\n              initial={reduce ? false : { opacity: 0 }}\n              animate={{ opacity: 1 }}\n              exit={reduce ? { opacity: 1 } : { opacity: 0 }}\n              transition={{ duration: 0.2, ease: \"easeOut\" }}\n            />\n            <div className=\"pointer-events-none fixed inset-0 z-50 flex items-center justify-center p-4\">\n              <motion.div\n                ref={panelRef}\n                role=\"alertdialog\"\n                aria-modal=\"true\"\n                tabIndex={-1}\n                onClick={(e) => e.stopPropagation()}\n                className={cn(\n                  \"pointer-events-auto w-full overflow-hidden rounded-xl border border-border bg-popover text-popover-foreground shadow-lg outline-none\",\n                  panelWidth[size],\n                  className\n                )}\n                initial={reduce ? false : { opacity: 0, scale: 0.96, y: 8 }}\n                animate={{ opacity: 1, scale: 1, y: 0 }}\n                exit={reduce ? { opacity: 1 } : { opacity: 0, scale: 0.96, y: 8 }}\n                transition={{ duration: 0.2, ease: \"easeOut\" }}\n              >\n                <Illustration\n                  variant={variant}\n                  tone={tone}\n                  icon={icon}\n                  size={size}\n                  reduce={reduce}\n                />\n\n                <div\n                  data-tone={tone}\n                  className={cn(\"flex flex-col items-center text-center\", bodyPad[size])}\n                >\n                  {title ? (\n                    <h2\n                      data-slot=\"styled-alert-dialog-title\"\n                      className=\"text-base font-semibold tracking-tight text-foreground\"\n                    >\n                      {title}\n                    </h2>\n                  ) : null}\n                  {description ? (\n                    <p\n                      data-slot=\"styled-alert-dialog-description\"\n                      className=\"mt-1 text-sm text-muted-foreground\"\n                    >\n                      {description}\n                    </p>\n                  ) : null}\n\n                  <div\n                    data-slot=\"styled-alert-dialog-footer\"\n                    className=\"mt-5 flex w-full flex-col-reverse gap-2 sm:flex-row sm:justify-center\"\n                  >\n                    <button\n                      type=\"button\"\n                      data-slot=\"styled-alert-dialog-cancel\"\n                      className={cancelBtn}\n                      onClick={() => setOpen(false)}\n                    >\n                      {cancelLabel}\n                    </button>\n                    <button\n                      type=\"button\"\n                      data-slot=\"styled-alert-dialog-confirm\"\n                      className={cn(confirmBtn, confirmTone[tone])}\n                      onClick={handleConfirm}\n                    >\n                      {confirmLabel}\n                    </button>\n                  </div>\n                </div>\n              </motion.div>\n            </div>\n          </>\n        ) : null}\n      </AnimatePresence>\n    </span>\n  )\n}\n\n/* SpotlightAlert: ustte radial token spotlight isik havuzu, ortada yuzen daire\n   icinde tone ikon. */\nexport function SpotlightAlert({\n  title = \"You are in the spotlight\",\n  description = \"Confirm to continue with this highlighted action.\",\n  ...props\n}: StyledAlertPublicProps) {\n  return (\n    <IllustratedAlertDialog\n      variant=\"spotlight\"\n      tone=\"info\"\n      icon={<Info />}\n      title={title}\n      description={description}\n      {...props}\n    />\n  )\n}\n\n/* BadgeAlert: ustte buyuk token yumusak-daire rozet, icinde tone ikon. */\nexport function BadgeAlert({\n  title = \"Badge earned\",\n  description = \"Confirm to apply this change to your account.\",\n  ...props\n}: StyledAlertPublicProps) {\n  return (\n    <IllustratedAlertDialog\n      variant=\"badge\"\n      tone=\"success\"\n      icon={<CheckCircle />}\n      title={title}\n      description={description}\n      {...props}\n    />\n  )\n}\n\n/* CircleAlert: ic ice token halkalar ortasinda tone ikon. */\nexport function CircleAlert({\n  title = \"Heads up\",\n  description = \"Please review this before you confirm the action.\",\n  ...props\n}: StyledAlertPublicProps) {\n  return (\n    <IllustratedAlertDialog\n      variant=\"circle\"\n      tone=\"warning\"\n      icon={<AlertTriangle />}\n      title={title}\n      description={description}\n      {...props}\n    />\n  )\n}\n\n/* GradientAlert: ustte tone gradient bant, ortada yuzen kutu icinde tone ikon. */\nexport function GradientAlert({\n  title = \"One more step\",\n  description = \"Confirm to move forward with this action.\",\n  ...props\n}: StyledAlertPublicProps) {\n  return (\n    <IllustratedAlertDialog\n      variant=\"gradient\"\n      tone=\"brand\"\n      icon={<Bell />}\n      title={title}\n      description={description}\n      {...props}\n    />\n  )\n}\n\n/* BannerAlert: a full-width token banner on top (top line plus a soft fill) with a tone icon in the middle. */\nexport function BannerAlert({\n  title = \"Delete this item?\",\n  description = \"This action cannot be undone once confirmed.\",\n  confirmLabel = \"Delete\",\n  ...props\n}: StyledAlertPublicProps) {\n  return (\n    <IllustratedAlertDialog\n      variant=\"banner\"\n      tone=\"danger\"\n      icon={<AlertTriangle />}\n      title={title}\n      description={description}\n      confirmLabel={confirmLabel}\n      {...props}\n    />\n  )\n}\n",
      "type": "registry:component",
      "target": "components/ui/alert-dialog-illustration.tsx"
    }
  ],
  "categories": [
    "styled",
    "alert"
  ],
  "type": "registry:component"
}