{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "alert-dialog",
  "title": "Alert dialog",
  "author": "andongmin94",
  "description": "A modal confirmation dialog for important or destructive actions.",
  "dependencies": [
    "@base-ui/react@^1.6.0"
  ],
  "registryDependencies": [
    "https://neobrutal-ui.andongmin.com/r/button.json"
  ],
  "files": [
    {
      "path": "src/components/ui/alert-dialog.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { AlertDialog as AlertDialogPrimitive } from \"@base-ui/react/alert-dialog\";\n\nimport { cn } from \"@/lib/utils\";\nimport { Button } from \"@/components/ui/button\";\n\ntype AutoFocusEventHandler = (event: Event) => void;\ntype FocusTarget = AlertDialogPrimitive.Popup.Props[\"initialFocus\"];\ntype PointerDownOutsideEvent = CustomEvent<{ originalEvent: PointerEvent }>;\ntype FocusOutsideEvent = CustomEvent<{ originalEvent: FocusEvent }>;\ntype DismissableLayerHandlers = {\n  onEscapeKeyDown?: (event: KeyboardEvent) => void;\n  onFocusOutside?: (event: FocusOutsideEvent) => void;\n  onInteractOutside?: (event: FocusOutsideEvent | PointerDownOutsideEvent) => void;\n  onPointerDownOutside?: (event: PointerDownOutsideEvent) => void;\n};\ntype AlertDialogPortalProps = AlertDialogPrimitive.Portal.Props & {\n  forceMount?: boolean;\n};\ntype AlertDialogOverlayProps = AlertDialogPrimitive.Backdrop.Props & {\n  asChild?: boolean;\n  children?: React.ReactNode;\n  forceMount?: boolean;\n};\ntype AlertDialogContentProps = AlertDialogPrimitive.Popup.Props & {\n  asChild?: boolean;\n  children?: React.ReactNode;\n  forceMount?: boolean;\n  onCloseAutoFocus?: AutoFocusEventHandler;\n  onOpenAutoFocus?: AutoFocusEventHandler;\n  size?: \"default\" | \"sm\";\n} & DismissableLayerHandlers;\ntype AlertDialogButtonProps = React.ComponentProps<typeof AlertDialogPrimitive.Close> &\n  Pick<React.ComponentProps<typeof Button>, \"variant\" | \"size\"> & {\n    asChild?: boolean;\n    children?: React.ReactNode;\n  };\ntype AlertDialogContextProps = {\n  cancelRef: React.RefObject<HTMLButtonElement | null>;\n  dismissableLayerHandlersRef: React.RefObject<DismissableLayerHandlers>;\n  open: boolean;\n};\n\ntype PreventableBaseUIEvent = {\n  readonly baseUIHandlerPrevented?: boolean;\n  readonly defaultPrevented?: boolean;\n  preventBaseUIHandler?: () => void;\n};\ntype EventHandler = (...args: unknown[]) => unknown;\ntype RenderFunction = (props: Record<string, unknown>, state: unknown) => React.ReactElement;\n\nfunction adaptEventHandlers(props: Record<string, unknown>, beforeBaseUIHandler: boolean) {\n  const eventHandlers: Record<string, EventHandler> = {};\n\n  for (const [name, handler] of Object.entries(props)) {\n    if (!/^on[A-Z]/.test(name) || typeof handler !== \"function\") {\n      continue;\n    }\n\n    eventHandlers[name] = (...args) => {\n      const event = args[0] as PreventableBaseUIEvent | undefined;\n      if (beforeBaseUIHandler && event?.defaultPrevented) {\n        event.preventBaseUIHandler?.();\n      }\n      if (beforeBaseUIHandler && event?.baseUIHandlerPrevented) {\n        return undefined;\n      }\n\n      const result = handler(...args);\n      if (!beforeBaseUIHandler && event?.defaultPrevented) {\n        event.preventBaseUIHandler?.();\n      }\n      return result;\n    };\n  }\n\n  return eventHandlers;\n}\n\nfunction adaptRenderEventHandlers<Render>(render: Render): Render {\n  if (React.isValidElement(render)) {\n    const element = render as React.ReactElement<Record<string, unknown>>;\n    const eventHandlers = adaptEventHandlers(element.props, false);\n    return (Object.keys(eventHandlers).length === 0\n      ? render\n      : React.cloneElement(element, eventHandlers)) as unknown as Render;\n  }\n  if (typeof render === \"function\") {\n    const renderFunction = render as RenderFunction;\n    return ((props: Record<string, unknown>, state: unknown) =>\n      renderFunction({ ...props, ...adaptEventHandlers(props, true) }, state)) as unknown as Render;\n  }\n  return render;\n}\n\nconst AlertDialogContext = React.createContext<AlertDialogContextProps | null>(null);\n\nfunction useAlertDialogContext() {\n  const context = React.useContext(AlertDialogContext);\n\n  if (!context) {\n    throw new Error(\"AlertDialog components must be used within AlertDialog.\");\n  }\n\n  return context;\n}\n\nfunction createPointerEvent(event: MouseEvent | PointerEvent | TouchEvent): PointerEvent {\n  if (\"pointerId\" in event) {\n    return event;\n  }\n\n  const touch = \"changedTouches\" in event ? event.changedTouches[0] : undefined;\n  const ownerDocument = event.target instanceof Node ? event.target.ownerDocument : null;\n  const view = ownerDocument?.defaultView ?? window;\n  const PointerEventConstructor = view?.PointerEvent;\n\n  if (!PointerEventConstructor) {\n    return event as PointerEvent;\n  }\n\n  return new PointerEventConstructor(\"pointerdown\", {\n    bubbles: event.bubbles,\n    button: \"button\" in event ? event.button : 0,\n    buttons: \"buttons\" in event ? event.buttons : 1,\n    cancelable: event.cancelable,\n    clientX: touch?.clientX ?? (\"clientX\" in event ? event.clientX : 0),\n    clientY: touch?.clientY ?? (\"clientY\" in event ? event.clientY : 0),\n    composed: event.composed,\n    ctrlKey: \"ctrlKey\" in event && event.ctrlKey,\n    metaKey: \"metaKey\" in event && event.metaKey,\n    pointerType: \"changedTouches\" in event ? \"touch\" : \"mouse\",\n    shiftKey: \"shiftKey\" in event && event.shiftKey,\n  });\n}\n\nfunction createPointerDownOutsideEvent(\n  originalEvent: MouseEvent | PointerEvent | TouchEvent,\n): PointerDownOutsideEvent {\n  const event = new CustomEvent<{ originalEvent: PointerEvent }>(\n    \"dismissableLayer.pointerDownOutside\",\n    {\n      cancelable: true,\n      detail: { originalEvent: createPointerEvent(originalEvent) },\n    },\n  );\n  Object.defineProperty(event, \"target\", { configurable: true, value: originalEvent.target });\n  return event;\n}\n\nfunction createFocusOutsideEvent(originalEvent: FocusEvent | KeyboardEvent): FocusOutsideEvent {\n  const focusEvent =\n    \"relatedTarget\" in originalEvent\n      ? originalEvent\n      : new FocusEvent(\"focusin\", { bubbles: true, cancelable: true });\n  const event = new CustomEvent<{ originalEvent: FocusEvent }>(\"dismissableLayer.focusOutside\", {\n    cancelable: true,\n    detail: { originalEvent: focusEvent },\n  });\n  Object.defineProperty(event, \"target\", { configurable: true, value: originalEvent.target });\n  return event;\n}\n\nfunction adaptDismissableLayerEvent(\n  eventDetails: AlertDialogPrimitive.Root.ChangeEventDetails,\n  handlers: DismissableLayerHandlers,\n) {\n  if (eventDetails.reason === \"escape-key\") {\n    handlers.onEscapeKeyDown?.(eventDetails.event);\n    if (eventDetails.event.defaultPrevented) {\n      eventDetails.cancel();\n    }\n    return;\n  }\n\n  if (eventDetails.reason === \"outside-press\") {\n    const event = createPointerDownOutsideEvent(eventDetails.event);\n    handlers.onPointerDownOutside?.(event);\n    handlers.onInteractOutside?.(event);\n    if (event.defaultPrevented) {\n      eventDetails.cancel();\n    }\n    return;\n  }\n\n  if (eventDetails.reason === \"focus-out\") {\n    const event = createFocusOutsideEvent(eventDetails.event);\n    handlers.onFocusOutside?.(event);\n    handlers.onInteractOutside?.(event);\n    if (event.defaultPrevented) {\n      eventDetails.cancel();\n    }\n  }\n}\n\nfunction adaptCloseClick(\n  handler: AlertDialogPrimitive.Close.Props[\"onClick\"],\n): AlertDialogPrimitive.Close.Props[\"onClick\"] {\n  if (!handler) {\n    return undefined;\n  }\n\n  return (event) => {\n    handler(event);\n    if (event.defaultPrevented) {\n      event.preventBaseUIHandler();\n    }\n  };\n}\n\nfunction setRef<T>(ref: React.Ref<T> | undefined, value: T | null) {\n  if (typeof ref === \"function\") {\n    ref(value);\n  } else if (ref) {\n    ref.current = value;\n  }\n}\n\nfunction hasForceMountedChild(children: React.ReactNode) {\n  return React.Children.toArray(children).some(\n    (child) => React.isValidElement<{ forceMount?: boolean }>(child) && child.props.forceMount,\n  );\n}\n\nfunction adaptAutoFocus(\n  handler: AutoFocusEventHandler | undefined,\n  focus: FocusTarget,\n  eventName: string,\n): FocusTarget {\n  if (!handler) {\n    return focus;\n  }\n\n  return (interactionType) => {\n    const event = new Event(eventName, { cancelable: true });\n    handler(event);\n\n    if (event.defaultPrevented) {\n      return false;\n    }\n\n    if (typeof focus === \"function\") {\n      return focus(interactionType);\n    }\n\n    if (typeof focus === \"object\" && focus !== null) {\n      return focus.current;\n    }\n\n    return typeof focus === \"boolean\" ? focus : true;\n  };\n}\n\nfunction AlertDialog({\n  defaultOpen = false,\n  onOpenChange,\n  open,\n  ...props\n}: AlertDialogPrimitive.Root.Props) {\n  const cancelRef = React.useRef<HTMLButtonElement>(null);\n  const dismissableLayerHandlersRef = React.useRef<DismissableLayerHandlers>({});\n  const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen);\n  const resolvedOpen = open ?? uncontrolledOpen;\n  const contextValue = React.useMemo(\n    () => ({ cancelRef, dismissableLayerHandlersRef, open: resolvedOpen }),\n    [resolvedOpen],\n  );\n\n  const handleOpenChange: NonNullable<AlertDialogPrimitive.Root.Props[\"onOpenChange\"]> = (\n    nextOpen,\n    eventDetails,\n  ) => {\n    if (!nextOpen) {\n      adaptDismissableLayerEvent(eventDetails, dismissableLayerHandlersRef.current);\n    }\n    if (eventDetails.isCanceled) {\n      return;\n    }\n    if (open === undefined) {\n      setUncontrolledOpen(nextOpen);\n    }\n    onOpenChange?.(nextOpen, eventDetails);\n  };\n\n  return (\n    <AlertDialogContext.Provider value={contextValue}>\n      <AlertDialogPrimitive.Root\n        data-slot=\"alert-dialog\"\n        defaultOpen={defaultOpen}\n        open={open}\n        {...props}\n        onOpenChange={handleOpenChange}\n      />\n    </AlertDialogContext.Provider>\n  );\n}\n\nfunction AlertDialogTrigger({\n  asChild = false,\n  children,\n  render,\n  ...props\n}: AlertDialogPrimitive.Trigger.Props & {\n  asChild?: boolean;\n  children?: React.ReactNode;\n}) {\n  const { open } = useAlertDialogContext();\n  const renderElement = asChild\n    ? (React.Children.toArray(children).find(React.isValidElement) as React.ReactElement)\n    : render;\n\n  return (\n    <AlertDialogPrimitive.Trigger\n      data-slot=\"alert-dialog-trigger\"\n      data-state={open ? \"open\" : \"closed\"}\n      render={adaptRenderEventHandlers(renderElement)}\n      {...props}\n    >\n      {asChild ? undefined : children}\n    </AlertDialogPrimitive.Trigger>\n  );\n}\n\nfunction AlertDialogPortal({ forceMount, keepMounted, ...props }: AlertDialogPortalProps) {\n  const keepPortalMounted = forceMount ?? (hasForceMountedChild(props.children) || keepMounted);\n\n  return (\n    <AlertDialogPrimitive.Portal\n      data-slot=\"alert-dialog-portal\"\n      keepMounted={keepPortalMounted}\n      {...props}\n    />\n  );\n}\n\nfunction AlertDialogOverlay({\n  asChild = false,\n  children,\n  className,\n  forceMount: _forceMount,\n  render,\n  ...props\n}: AlertDialogOverlayProps) {\n  const { open } = useAlertDialogContext();\n  const renderElement = asChild\n    ? (React.Children.toArray(children).find(React.isValidElement) as React.ReactElement)\n    : render;\n\n  return (\n    <AlertDialogPrimitive.Backdrop\n      data-slot=\"alert-dialog-overlay\"\n      data-state={open ? \"open\" : \"closed\"}\n      render={adaptRenderEventHandlers(renderElement)}\n      className={cn(\n        \"fixed inset-0 isolate z-50 bg-overlay duration-200 data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0\",\n        className,\n      )}\n      {...props}\n    >\n      {asChild ? undefined : children}\n    </AlertDialogPrimitive.Backdrop>\n  );\n}\n\nfunction AlertDialogContent({\n  asChild = false,\n  className,\n  children,\n  finalFocus,\n  forceMount,\n  initialFocus,\n  onCloseAutoFocus,\n  onEscapeKeyDown,\n  onFocusOutside,\n  onInteractOutside,\n  onOpenAutoFocus,\n  onPointerDownOutside,\n  render,\n  size = \"default\",\n  ...props\n}: AlertDialogContentProps) {\n  const { cancelRef, dismissableLayerHandlersRef, open } = useAlertDialogContext();\n  const dismissableLayerHandlers = React.useMemo(\n    () => ({ onEscapeKeyDown, onFocusOutside, onInteractOutside, onPointerDownOutside }),\n    [onEscapeKeyDown, onFocusOutside, onInteractOutside, onPointerDownOutside],\n  );\n  const defaultInitialFocus = React.useCallback(() => cancelRef.current ?? false, [cancelRef]);\n  const renderElement = asChild\n    ? (React.Children.toArray(children).find(React.isValidElement) as React.ReactElement)\n    : render;\n  dismissableLayerHandlersRef.current = dismissableLayerHandlers;\n\n  React.useEffect(\n    () => () => {\n      if (dismissableLayerHandlersRef.current === dismissableLayerHandlers) {\n        dismissableLayerHandlersRef.current = {};\n      }\n    },\n    [dismissableLayerHandlers, dismissableLayerHandlersRef],\n  );\n\n  return (\n    <AlertDialogPortal forceMount={forceMount}>\n      <AlertDialogOverlay />\n      <AlertDialogPrimitive.Popup\n        data-slot=\"alert-dialog-content\"\n        data-size={size}\n        data-state={open ? \"open\" : \"closed\"}\n        render={adaptRenderEventHandlers(renderElement)}\n        initialFocus={adaptAutoFocus(\n          onOpenAutoFocus,\n          initialFocus === undefined ? defaultInitialFocus : initialFocus,\n          \"focusScope.autoFocusOnMount\",\n        )}\n        finalFocus={adaptAutoFocus(onCloseAutoFocus, finalFocus, \"focusScope.autoFocusOnUnmount\")}\n        className={cn(\n          \"group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 rounded-base border-2 border-border bg-background p-6 text-foreground shadow-shadow duration-200 outline-none data-[size=default]:sm:max-w-lg data-[size=sm]:sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95\",\n          className,\n        )}\n        {...props}\n      >\n        {asChild ? undefined : children}\n      </AlertDialogPrimitive.Popup>\n    </AlertDialogPortal>\n  );\n}\n\nfunction AlertDialogHeader({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"alert-dialog-header\"\n      className={cn(\"flex flex-col gap-2 text-center sm:text-left\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction AlertDialogFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"alert-dialog-footer\"\n      className={cn(\"flex flex-col-reverse gap-3 sm:flex-row sm:justify-end\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction AlertDialogMedia({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"alert-dialog-media\"\n      className={cn(\n        \"mb-2 inline-flex size-10 items-center justify-center rounded-base border-2 border-border bg-main text-main-foreground shadow-shadow *:[svg:not([class*='size-'])]:size-6\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction AlertDialogTitle({\n  asChild = false,\n  children,\n  className,\n  render,\n  ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Title> & {\n  asChild?: boolean;\n  children?: React.ReactNode;\n}) {\n  const renderElement = asChild\n    ? (React.Children.toArray(children).find(React.isValidElement) as React.ReactElement)\n    : render;\n\n  return (\n    <AlertDialogPrimitive.Title\n      data-slot=\"alert-dialog-title\"\n      render={adaptRenderEventHandlers(renderElement)}\n      className={cn(\"font-heading text-lg\", className)}\n      {...props}\n    >\n      {asChild ? undefined : children}\n    </AlertDialogPrimitive.Title>\n  );\n}\n\nfunction AlertDialogDescription({\n  asChild = false,\n  children,\n  className,\n  render,\n  ...props\n}: React.ComponentProps<typeof AlertDialogPrimitive.Description> & {\n  asChild?: boolean;\n  children?: React.ReactNode;\n}) {\n  const renderElement = asChild\n    ? (React.Children.toArray(children).find(React.isValidElement) as React.ReactElement)\n    : render;\n\n  return (\n    <AlertDialogPrimitive.Description\n      data-slot=\"alert-dialog-description\"\n      render={adaptRenderEventHandlers(renderElement)}\n      className={cn(\"text-sm font-base text-foreground\", className)}\n      {...props}\n    >\n      {asChild ? undefined : children}\n    </AlertDialogPrimitive.Description>\n  );\n}\n\nfunction AlertDialogAction({\n  asChild = false,\n  children,\n  className,\n  onClick,\n  render,\n  size = \"default\",\n  variant = \"default\",\n  ...props\n}: AlertDialogButtonProps) {\n  const renderElement = asChild\n    ? (React.Children.toArray(children).find(React.isValidElement) as React.ReactElement)\n    : (render ?? <Button variant={variant} size={size} />);\n\n  return (\n    <AlertDialogPrimitive.Close\n      data-slot=\"alert-dialog-action\"\n      className={cn(className)}\n      onClick={adaptCloseClick(onClick)}\n      render={adaptRenderEventHandlers(renderElement)}\n      {...props}\n    >\n      {asChild ? undefined : children}\n    </AlertDialogPrimitive.Close>\n  );\n}\n\nfunction AlertDialogCancel({\n  className,\n  variant = \"neutral\",\n  size = \"default\",\n  asChild = false,\n  children,\n  onClick,\n  ref: forwardedRef,\n  render,\n  ...props\n}: AlertDialogButtonProps) {\n  const { cancelRef } = useAlertDialogContext();\n  const renderElement = asChild\n    ? (React.Children.toArray(children).find(React.isValidElement) as React.ReactElement)\n    : (render ?? <Button variant={variant} size={size} />);\n  const composedRef = React.useCallback(\n    (element: HTMLButtonElement | null) => {\n      cancelRef.current = element;\n      setRef(forwardedRef, element);\n    },\n    [cancelRef, forwardedRef],\n  );\n\n  return (\n    <AlertDialogPrimitive.Close\n      data-slot=\"alert-dialog-cancel\"\n      className={cn(className)}\n      onClick={adaptCloseClick(onClick)}\n      ref={composedRef}\n      render={adaptRenderEventHandlers(renderElement)}\n      {...props}\n    >\n      {asChild ? undefined : children}\n    </AlertDialogPrimitive.Close>\n  );\n}\n\nexport {\n  AlertDialog,\n  AlertDialogAction,\n  AlertDialogCancel,\n  AlertDialogContent,\n  AlertDialogDescription,\n  AlertDialogFooter,\n  AlertDialogHeader,\n  AlertDialogMedia,\n  AlertDialogOverlay,\n  AlertDialogPortal,\n  AlertDialogTitle,\n  AlertDialogTrigger,\n};\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "overlay",
    "dialog",
    "feedback"
  ],
  "type": "registry:ui"
}