{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "alert-dialog-glass",
  "title": "Dialog-glass alert",
  "description": "Styled alert: the Dialog-glass set. 5 decorative alert variations (FrostAlert, TintAlert, DarkAlert, BlurAlert, CrystalAlert) 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",
    "@ai2/glass"
  ],
  "files": [
    {
      "path": "registry/ai2/styled/alert-dialog-glass.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Gem, MoonStar, Snowflake, Sparkles, Wind } from \"lucide-react\"\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { glassDepth } from \"@/registry/ai2/ui/glass\"\n\n/* Glass alert-dialog family: 5 frosted-glass confirmation windows. A different\n   direction from Essentials: there the panel is opaque and the difference lives\n   in tone and icon; here the panel ITSELF is frosted glass and the difference\n   lives in the glass surface and the backdrop technique. Every export is a\n   complete modal: internal state (uncontrolled defaultOpen or controlled\n   open/onOpenChange), SELF-CONTAINED (no radix, no portal) - a fixed backdrop\n   plus a centred fixed panel. A backdrop click, Escape or Cancel closes it;\n   Confirm calls onConfirm first and then closes. The panel takes focus on open.\n   AnimatePresence enter/exit, only a fade under reduced motion. Colour comes\n   ONLY from tokens, translucency via color-mix. The confirm button is driven by\n   the tone token (exactly the same structure as Essentials).\n\n   The PANEL glass surface derives from the glassDepth scale in @ai2/glass\n   (AGENTS.md 4.5). Because this family is a modal it sits at the top of the\n   scale: a modal panel really should hide what is behind it. The shared panel\n   class no longer carries shadow-lg - it is in the same tailwind-merge group as\n   the glassDepth signature, and keeping it would silently drop that signature.\n\n   The BACKDROP deliberately does NOT use glassDepth: it is a full-screen scrim,\n   not a glass surface. glassDepth's inset highlight would draw a bright line\n   from one edge of the screen to the other. The scrim's blur stays hand-written\n   here. */\n\nexport type StyledSize = \"sm\" | \"md\" | \"lg\" | \"xl\"\n\nexport type StyledTone = \"info\" | \"success\" | \"warning\" | \"danger\"\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/* 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}\n\nconst cancelBtn =\n  \"inline-flex h-9 items-center justify-center rounded-md border border-[color-mix(in_oklab,var(--color-border)_70%,transparent)] bg-[color-mix(in_oklab,var(--color-background)_35%,transparent)] px-4 text-sm font-medium text-foreground transition-colors hover:bg-[color-mix(in_oklab,var(--color-foreground)_8%,transparent)] 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 StyledAlertCoreProps = StyledAlertPublicProps & {\n  tone: StyledTone\n  confirmClassName: string\n  icon: React.ReactNode\n  iconClassName: string\n  /* Cam panelin yuzey teknigi (translucency + backdrop-blur + kenar). */\n  panelClassName: string\n  /* Backdrop scrim + blur teknigi. */\n  backdropClassName: string\n}\n\n/* Shared modal core: state management, backdrop, glass panel, escape, focus,\n   motion. The panel and backdrop appearance change through the class each\n   variant passes in; the tone/icon/confirm plumbing is identical to\n   Essentials. */\nfunction GlassAlertDialog({\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  confirmClassName,\n  icon,\n  iconClassName,\n  panelClassName,\n  backdropClassName,\n}: StyledAlertCoreProps) {\n  const reduce = useReducedMotion()\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={cn(\"fixed inset-0 z-50\", backdropClassName)}\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 rounded-xl border text-popover-foreground outline-none\",\n                  panelClassName,\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                <div data-tone={tone} className={cn(\"flex flex-col\", bodyPad[size])}>\n                  <div className=\"flex gap-3\">\n                    <span\n                      data-slot=\"styled-alert-dialog-icon\"\n                      className={cn(\n                        \"mt-0.5 flex shrink-0 items-center [&_svg]:size-5 [&_svg]:shrink-0 [&_i]:text-xl [&_i]:leading-none\",\n                        iconClassName\n                      )}\n                    >\n                      {icon}\n                    </span>\n                    <div className=\"min-w-0 flex-1\">\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                    </div>\n                  </div>\n\n                  <div\n                    data-slot=\"styled-alert-dialog-footer\"\n                    className=\"mt-5 flex justify-end gap-2\"\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, confirmClassName)}\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/* FrostAlert: neutral frosted glass. The general-purpose glass confirmation\n   window.\n   Depth lg (16px): a modal wants the page behind it to be texture, not text.\n   The neutral ground is left to the library (the old hand-written 68% was very\n   close to popover's background/70); the character is the soft border. */\nexport function FrostAlert({\n  title = \"Confirm this action?\",\n  description = \"A frosted panel over the page. Confirm to continue.\",\n  ...props\n}: StyledAlertPublicProps) {\n  return (\n    <GlassAlertDialog\n      tone=\"info\"\n      icon={<Snowflake />}\n      iconClassName=\"text-info\"\n      confirmClassName=\"bg-primary text-primary-foreground hover:bg-primary/90\"\n      panelClassName={cn(\n        glassDepth.lg,\n        \"border-[color-mix(in_oklab,var(--color-border)_70%,transparent)]\"\n      )}\n      backdropClassName=\"bg-[color-mix(in_oklab,var(--color-foreground)_30%,transparent)] supports-[backdrop-filter]:backdrop-blur-sm\"\n      title={title}\n      description={description}\n      {...props}\n    />\n  )\n}\n\n/* TintAlert: info-tinted glass. The surface is filmed with info and the border\n   takes the info tone.\n   Depth md (8px): deliberately one step behind Frost - what hides the\n   background here is not the blur but the info film itself. That way Tint reads\n   as a separate surface next to Frost. The ground is overridden in both forms\n   (with and without @supports). */\nexport function TintAlert({\n  title = \"Apply changes?\",\n  description = \"An info-tinted glass surface. Confirm to apply.\",\n  ...props\n}: StyledAlertPublicProps) {\n  return (\n    <GlassAlertDialog\n      tone=\"info\"\n      icon={<Sparkles />}\n      iconClassName=\"text-info\"\n      confirmClassName=\"bg-primary text-primary-foreground hover:bg-primary/90\"\n      panelClassName={cn(\n        glassDepth.md,\n        \"border-[color-mix(in_oklab,var(--color-info)_35%,transparent)]\",\n        \"bg-[color-mix(in_oklab,var(--color-info)_16%,transparent)] supports-[backdrop-filter]:bg-[color-mix(in_oklab,var(--color-info)_16%,transparent)]\"\n      )}\n      backdropClassName=\"bg-[color-mix(in_oklab,var(--color-info)_30%,transparent)] supports-[backdrop-filter]:backdrop-blur-sm\"\n      title={title}\n      description={description}\n      {...props}\n    />\n  )\n}\n\n/* DarkAlert: dark frosted glass. A foreground-based smoky surface with a strong\n   scrim. Works against foreground in both themes.\n   Depth lg (16px): the old value was 16px too - it landed exactly on the scale.\n   The same step as Frost, because both play the \"modal\" role; the smoke is what\n   separates them. */\nexport function DarkAlert({\n  title = \"Proceed in the dark?\",\n  description = \"A smoky glass panel with a heavier scrim. Confirm to continue.\",\n  ...props\n}: StyledAlertPublicProps) {\n  return (\n    <GlassAlertDialog\n      tone=\"info\"\n      icon={<MoonStar />}\n      iconClassName=\"text-info\"\n      confirmClassName={confirmTone.info}\n      panelClassName={cn(\n        glassDepth.lg,\n        \"border-[color-mix(in_oklab,var(--color-foreground)_22%,transparent)]\",\n        \"bg-[color-mix(in_oklab,var(--color-foreground)_16%,transparent)] supports-[backdrop-filter]:bg-[color-mix(in_oklab,var(--color-foreground)_16%,transparent)]\"\n      )}\n      backdropClassName=\"bg-[color-mix(in_oklab,var(--color-foreground)_60%,transparent)] supports-[backdrop-filter]:backdrop-blur-md\"\n      title={title}\n      description={description}\n      {...props}\n    />\n  )\n}\n\n/* BlurAlert: a light film where the highest blur scatters the background\n   completely. Focus stays on the modal.\n   Depth xl (24px): the far end of the scale - the family's only maximum-scatter\n   member, which is the whole identity of this variant. The old 64px was off the\n   scale; xl does the same job. */\nexport function BlurAlert({\n  title = \"Focus here for a moment\",\n  description = \"The page behind is fully diffused. Confirm to continue.\",\n  ...props\n}: StyledAlertPublicProps) {\n  return (\n    <GlassAlertDialog\n      tone=\"info\"\n      icon={<Wind />}\n      iconClassName=\"text-foreground\"\n      confirmClassName=\"bg-primary text-primary-foreground hover:bg-primary/90\"\n      panelClassName={cn(\n        glassDepth.xl,\n        \"border-[color-mix(in_oklab,var(--color-border)_60%,transparent)]\",\n        \"bg-[color-mix(in_oklab,var(--color-popover)_55%,transparent)] supports-[backdrop-filter]:bg-[color-mix(in_oklab,var(--color-popover)_55%,transparent)]\"\n      )}\n      backdropClassName=\"bg-[color-mix(in_oklab,var(--color-foreground)_25%,transparent)] supports-[backdrop-filter]:backdrop-blur-lg\"\n      title={title}\n      description={description}\n      {...props}\n    />\n  )\n}\n\n/* CrystalAlert: a clear surface with a crystal edge.\n   Depth md (8px): crystal means clarity, not scatter - deliberately the lowest\n   step in the modal family. The old shadow-[inset...] was REMOVED: being in the\n   same tailwind-merge group as the glassDepth signature, it was erasing that\n   signature - the thin bright line on top is already the signature's own inset\n   highlight and does not need repeating by hand. The crystal edge is driven by\n   an inset ring instead (which does not touch the shadow group). */\nexport function CrystalAlert({\n  title = \"Confirm with clarity\",\n  description = \"A crisp glass panel with a sharp inset highlight. Confirm to continue.\",\n  ...props\n}: StyledAlertPublicProps) {\n  return (\n    <GlassAlertDialog\n      tone=\"success\"\n      icon={<Gem />}\n      iconClassName=\"text-primary\"\n      confirmClassName=\"bg-primary text-primary-foreground hover:bg-primary/90\"\n      panelClassName={cn(\n        glassDepth.md,\n        \"border-[color-mix(in_oklab,var(--color-border)_65%,transparent)]\",\n        \"bg-[color-mix(in_oklab,var(--color-popover)_62%,transparent)] supports-[backdrop-filter]:bg-[color-mix(in_oklab,var(--color-popover)_62%,transparent)]\",\n        \"ring-1 ring-inset ring-[color-mix(in_oklab,var(--color-background)_45%,transparent)]\"\n      )}\n      backdropClassName=\"bg-[color-mix(in_oklab,var(--color-foreground)_35%,transparent)] supports-[backdrop-filter]:backdrop-blur-sm\"\n      title={title}\n      description={description}\n      {...props}\n    />\n  )\n}\n",
      "type": "registry:component",
      "target": "components/ui/alert-dialog-glass.tsx"
    }
  ],
  "categories": [
    "styled",
    "alert"
  ],
  "type": "registry:component"
}