{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "alert-dialog-layout",
  "title": "Dialog-layout alert",
  "description": "Styled alert: the Dialog-layout set. 5 decorative alert variations (CenteredAlert, HorizontalAlert, CompactAlert, WideAlert, SplitAlert) 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-layout.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { AlertTriangle, CheckCircle, Info, Trash2 } from \"lucide-react\"\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\n\n/* Styled alert-dialog \"Layout\" family: 5 confirmation modals that share the same\n   plain panel look but differ in how content and buttons are arranged. Each\n   export is a complete modal: internal open state (uncontrolled defaultOpen /\n   controlled open+onOpenChange), SELF-CONTAINED (no radix, no portal) - fixed\n   backdrop + centered 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 handles enter/exit, and under reduced motion it fades or\n   switches instantly. Color comes ONLY from tokens, via alpha color-mix. The\n   panel stays neutral; the only thing that changes is the layout. The tone\n   tokens drive the icon and the confirm button. */\n\nexport type StyledSize = \"sm\" | \"md\" | \"lg\" | \"xl\"\n\nexport type StyledTone = \"info\" | \"success\" | \"warning\" | \"danger\"\n\ntype LayoutKind = \"centered\" | \"horizontal\" | \"compact\" | \"wide\" | \"split\"\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\n/* The Wide layout wants a wider panel; size still sets the max limit, but the base width goes up one step. */\nconst wideWidth: Record<StyledSize, string> = {\n  sm: \"max-w-md\",\n  md: \"max-w-lg\",\n  lg: \"max-w-xl\",\n  xl: \"max-w-2xl\",\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\n/* The top band colour of the split layout - the tone soft token. */\nconst bandTone: Record<StyledTone, string> = {\n  info: \"bg-info-soft text-info-soft-foreground\",\n  success: \"bg-success-soft text-success-soft-foreground\",\n  warning: \"bg-warning-soft text-warning-soft-foreground\",\n  danger: \"bg-danger-soft text-danger-soft-foreground\",\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\n/* Compact duzen daha kucuk butonlar kullanir. */\nconst cancelBtnSm =\n  \"inline-flex h-8 items-center justify-center rounded-md border border-border bg-transparent px-3 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 confirmBtnSm =\n  \"inline-flex h-8 items-center justify-center gap-1.5 rounded-md px-3 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  layout: LayoutKind\n}\n\n/* Shared modal core: state management, backdrop, panel, escape, focus, motion. The layout prop decides the body and footer placement; the panel appearance is fixed. */\nfunction StyledAlertDialog({\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  layout,\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  const width = layout === \"wide\" ? wideWidth[size] : panelWidth[size]\n\n  /* Button group: small buttons in compact, full-width stacked in centered, a right-aligned row otherwise. */\n  const cancelClass = layout === \"compact\" ? cancelBtnSm : cancelBtn\n  const confirmClass = layout === \"compact\" ? confirmBtnSm : confirmBtn\n\n  const footer = (\n    <div\n      data-slot=\"styled-alert-dialog-footer\"\n      className={cn(\n        \"flex gap-2\",\n        layout === \"centered\"\n          ? \"mt-5 flex-col\"\n          : layout === \"compact\"\n            ? \"mt-0 shrink-0 justify-end\"\n            : \"mt-5 justify-end\"\n      )}\n    >\n      <button\n        type=\"button\"\n        data-slot=\"styled-alert-dialog-cancel\"\n        className={cn(cancelClass, layout === \"centered\" && \"w-full\")}\n        onClick={() => setOpen(false)}\n      >\n        {cancelLabel}\n      </button>\n      <button\n        type=\"button\"\n        data-slot=\"styled-alert-dialog-confirm\"\n        className={cn(\n          confirmClass,\n          confirmClassName,\n          layout === \"centered\" && \"w-full\"\n        )}\n        onClick={handleConfirm}\n      >\n        {confirmLabel}\n      </button>\n    </div>\n  )\n\n  const titleNode = 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\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                data-tone={tone}\n                data-layout={layout}\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                  width,\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                {/* CENTERED: icon, title and text centred vertically, full-width buttons stacked. */}\n                {layout === \"centered\" ? (\n                  <div className={cn(\"flex flex-col items-center text-center\", bodyPad[size])}>\n                    <span\n                      data-slot=\"styled-alert-dialog-icon\"\n                      className={cn(\n                        \"mb-3 flex size-12 items-center justify-center rounded-full bg-[color-mix(in_oklab,currentColor_12%,transparent)] [&_svg]:size-6 [&_svg]:shrink-0 [&_i]:text-2xl [&_i]:leading-none\",\n                        iconClassName\n                      )}\n                    >\n                      {icon}\n                    </span>\n                    {titleNode}\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                    {footer}\n                  </div>\n                ) : null}\n\n                {/* HORIZONTAL: ikon solda, metin sagda; butonlar sag altta. */}\n                {layout === \"horizontal\" ? (\n                  <div 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 size-10 shrink-0 items-center justify-center rounded-full bg-[color-mix(in_oklab,currentColor_12%,transparent)] [&_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                        {titleNode}\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                    {footer}\n                  </div>\n                ) : null}\n\n                {/* COMPACT: a tight one-line confirmation - icon and title on the left, buttons on the same line on the right. */}\n                {layout === \"compact\" ? (\n                  <div className={cn(\"flex items-center gap-3\", bodyPad[size])}>\n                    <span\n                      data-slot=\"styled-alert-dialog-icon\"\n                      className={cn(\n                        \"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 truncate text-sm font-medium text-foreground\">\n                      {title}\n                    </div>\n                    {footer}\n                  </div>\n                ) : null}\n\n                {/* WIDE: a wide panel; the description reads as two columns. */}\n                {layout === \"wide\" ? (\n                  <div className={cn(\"flex flex-col\", bodyPad[size])}>\n                    <div className=\"flex items-center gap-3\">\n                      <span\n                        data-slot=\"styled-alert-dialog-icon\"\n                        className={cn(\n                          \"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                      {titleNode}\n                    </div>\n                    {description ? (\n                      <p\n                        data-slot=\"styled-alert-dialog-description\"\n                        className=\"mt-3 text-sm text-muted-foreground sm:columns-2 sm:gap-6\"\n                      >\n                        {description}\n                      </p>\n                    ) : null}\n                    {footer}\n                  </div>\n                ) : null}\n\n                {/* SPLIT: ustte renkli/token baslik bandi + altta icerik ve\n                    butonlar ayrik. */}\n                {layout === \"split\" ? (\n                  <>\n                    <div\n                      data-slot=\"styled-alert-dialog-band\"\n                      className={cn(\n                        \"flex items-center gap-3 border-b border-border px-5 py-4\",\n                        bandTone[tone]\n                      )}\n                    >\n                      <span\n                        data-slot=\"styled-alert-dialog-icon\"\n                        className=\"flex shrink-0 items-center [&_svg]:size-5 [&_svg]:shrink-0 [&_i]:text-xl [&_i]:leading-none\"\n                      >\n                        {icon}\n                      </span>\n                      <h2\n                        data-slot=\"styled-alert-dialog-title\"\n                        className=\"text-base font-semibold tracking-tight\"\n                      >\n                        {title}\n                      </h2>\n                    </div>\n                    <div className={cn(\"flex flex-col\", bodyPad[size])}>\n                      {description ? (\n                        <p\n                          data-slot=\"styled-alert-dialog-description\"\n                          className=\"text-sm text-muted-foreground\"\n                        >\n                          {description}\n                        </p>\n                      ) : null}\n                      {footer}\n                    </div>\n                  </>\n                ) : null}\n              </motion.div>\n            </div>\n          </>\n        ) : null}\n      </AnimatePresence>\n    </span>\n  )\n}\n\n/* CenteredAlert: icon, title and text centred vertically, full-width buttons stacked. A mobile-friendly layout that focuses everything on a single decision. */\nexport function CenteredAlert({\n  title = \"Confirm this action?\",\n  description = \"Take a moment to review before you continue.\",\n  ...props\n}: StyledAlertPublicProps) {\n  return (\n    <StyledAlertDialog\n      layout=\"centered\"\n      tone=\"info\"\n      icon={<Info />}\n      iconClassName=\"text-info\"\n      confirmClassName={confirmTone.info}\n      title={title}\n      description={description}\n      {...props}\n    />\n  )\n}\n\n/* HorizontalAlert: ikon solda, metin sagda, butonlar sag altta. Klasik yatay\n   onay satiri duzeni. */\nexport function HorizontalAlert({\n  title = \"Save your changes?\",\n  description = \"You have unsaved edits that will be lost if you leave now.\",\n  confirmLabel = \"Save\",\n  ...props\n}: StyledAlertPublicProps) {\n  return (\n    <StyledAlertDialog\n      layout=\"horizontal\"\n      tone=\"success\"\n      icon={<CheckCircle />}\n      iconClassName=\"text-success\"\n      confirmClassName={confirmTone.success}\n      title={title}\n      description={description}\n      confirmLabel={confirmLabel}\n      {...props}\n    />\n  )\n}\n\n/* CompactAlert: a tight one-line confirmation - icon, title and buttons on the same line. The narrowest layout, for quick yes/no decisions. */\nexport function CompactAlert({\n  title = \"Discard draft?\",\n  confirmLabel = \"Discard\",\n  ...props\n}: StyledAlertPublicProps) {\n  return (\n    <StyledAlertDialog\n      layout=\"compact\"\n      size=\"lg\"\n      tone=\"danger\"\n      icon={<Trash2 />}\n      iconClassName=\"text-danger\"\n      confirmClassName={confirmTone.danger}\n      title={title}\n      confirmLabel={confirmLabel}\n      {...props}\n    />\n  )\n}\n\n/* WideAlert: a wide panel; the description reads as two columns. A roomy layout for confirmations with long descriptions. */\nexport function WideAlert({\n  title = \"Review the terms\",\n  description = \"These changes apply to your entire workspace and take effect immediately. Members keep their current roles, existing links stay valid, and billing continues on the same cycle without interruption.\",\n  confirmLabel = \"Accept\",\n  ...props\n}: StyledAlertPublicProps) {\n  return (\n    <StyledAlertDialog\n      layout=\"wide\"\n      size=\"xl\"\n      tone=\"info\"\n      icon={<Info />}\n      iconClassName=\"text-info\"\n      confirmClassName={confirmTone.info}\n      title={title}\n      description={description}\n      confirmLabel={confirmLabel}\n      {...props}\n    />\n  )\n}\n\n/* SplitAlert: ustte renkli/token baslik bandi + altta icerik ve butonlar ayrik.\n   Baslik ile govdeyi gorsel olarak ayiran iki bolgeli duzen. */\nexport function SplitAlert({\n  title = \"Delete this project?\",\n  description = \"This action cannot be undone. All files and history in the project will be permanently removed.\",\n  confirmLabel = \"Delete\",\n  ...props\n}: StyledAlertPublicProps) {\n  return (\n    <StyledAlertDialog\n      layout=\"split\"\n      tone=\"warning\"\n      icon={<AlertTriangle />}\n      iconClassName=\"text-warning-soft-foreground\"\n      confirmClassName={confirmTone.warning}\n      title={title}\n      description={description}\n      confirmLabel={confirmLabel}\n      {...props}\n    />\n  )\n}\n",
      "type": "registry:component",
      "target": "components/ui/alert-dialog-layout.tsx"
    }
  ],
  "categories": [
    "styled",
    "alert"
  ],
  "type": "registry:component"
}