{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "responsive-dialog",
  "type": "registry:ui",
  "title": "Responsive dialog",
  "description": "Modal dialog on desktop that becomes a swipeable bottom drawer on mobile.",
  "dependencies": [],
  "registryDependencies": [
    "http://127.0.0.1:3000/r/button.json",
    "http://127.0.0.1:3000/r/core.json",
    "http://127.0.0.1:3000/r/dialog.json",
    "http://127.0.0.1:3000/r/drawer.json"
  ],
  "files": [
    {
      "path": "src/registry/sources/control-ui/ui/responsive-dialog.tsx",
      "target": "@components/control-ui/ui/responsive-dialog.tsx",
      "type": "registry:ui",
      "content": "\"use client\";\n\nimport type { ComponentProps } from \"react\";\nimport { createContext, useContext, useState, useSyncExternalStore } from \"react\";\nimport type { OpenChangeEventDetails, ResponsiveDialogContentProps, ResponsiveDialogProps } from \"@/components/control-ui/contracts\";\nimport { cn } from \"@/components/control-ui/lib/cn\";\nimport { Button } from \"@/components/control-ui/ui/button\";\nimport {\n  Dialog,\n  DialogClose,\n  type DialogCloseProps,\n  DialogContent,\n  DialogDescription,\n  DialogFooter,\n  DialogHeader,\n  DialogTitle,\n  DialogTrigger,\n} from \"@/components/control-ui/ui/dialog\";\nimport {\n  Drawer,\n  DrawerClose,\n  DrawerContent,\n  DrawerDescription,\n  DrawerFooter,\n  DrawerHeader,\n  DrawerTitle,\n  DrawerTrigger,\n} from \"@/components/control-ui/ui/drawer\";\n\nconst MOBILE_QUERY = \"(max-width: 767px)\";\nconst ResponsiveDialogContext = createContext<boolean | null>(null);\n\nfunction subscribeToMobileDialog(onStoreChange: () => void) {\n  const query = window.matchMedia(MOBILE_QUERY);\n  query.addEventListener(\"change\", onStoreChange);\n  return () => query.removeEventListener(\"change\", onStoreChange);\n}\n\nfunction getMobileDialogSnapshot() {\n  return window.matchMedia(MOBILE_QUERY).matches;\n}\n\nfunction getMobileDialogServerSnapshot() {\n  return false;\n}\n\nfunction useResponsiveDialogContext() {\n  const isMobile = useContext(ResponsiveDialogContext);\n  if (isMobile === null) throw new Error(\"Responsive dialog parts must be used within ResponsiveDialog\");\n  return isMobile;\n}\n\nexport function ResponsiveDialog({ open: controlledOpen, defaultOpen = false, onOpenChange, children }: ResponsiveDialogProps) {\n  const isMobile = useSyncExternalStore(subscribeToMobileDialog, getMobileDialogSnapshot, getMobileDialogServerSnapshot);\n  const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);\n  const open = controlledOpen ?? uncontrolledOpen;\n\n  function handleOpenChange(nextOpen: boolean, eventDetails: OpenChangeEventDetails) {\n    if (controlledOpen === undefined) setUncontrolledOpen(nextOpen);\n    onOpenChange?.(nextOpen, eventDetails);\n  }\n\n  return (\n    <ResponsiveDialogContext.Provider value={isMobile}>\n      {isMobile ? (\n        <Drawer open={open} onOpenChange={handleOpenChange} side=\"bottom\">\n          {children}\n        </Drawer>\n      ) : (\n        <Dialog open={open} onOpenChange={handleOpenChange}>\n          {children}\n        </Dialog>\n      )}\n    </ResponsiveDialogContext.Provider>\n  );\n}\n\nexport function ResponsiveDialogTrigger(props: ComponentProps<typeof DialogTrigger>) {\n  const isMobile = useResponsiveDialogContext();\n  return isMobile ? <DrawerTrigger {...props} /> : <DialogTrigger {...props} />;\n}\n\nexport function ResponsiveDialogClose({\n  className,\n  children,\n  variant = \"surface\",\n  size = \"sm\",\n  tone = \"neutral\",\n  ...props\n}: DialogCloseProps) {\n  const isMobile = useResponsiveDialogContext();\n\n  if (!isMobile) {\n    return (\n      <DialogClose className={className} variant={variant} size={size} tone={tone} {...props}>\n        {children}\n      </DialogClose>\n    );\n  }\n\n  return (\n    <DrawerClose\n      {...props}\n      render={(renderProps) => (\n        <Button {...renderProps} variant={variant} size={size} tone={tone} className={cn(renderProps.className, className)}>\n          {children}\n        </Button>\n      )}\n    />\n  );\n}\n\nexport function ResponsiveDialogContent({\n  className,\n  dialogClassName,\n  drawerClassName,\n  children,\n  showCloseButton = true,\n  ...props\n}: ResponsiveDialogContentProps) {\n  const isMobile = useResponsiveDialogContext();\n\n  if (!isMobile) {\n    return (\n      <DialogContent className={cn(className, dialogClassName)} showCloseButton={showCloseButton} {...props}>\n        {children}\n      </DialogContent>\n    );\n  }\n\n  return (\n    <DrawerContent className={cn(\"relative pb-[max(1rem,env(safe-area-inset-bottom))]\", className, drawerClassName)} {...props}>\n      {children}\n      {showCloseButton ? (\n        <ResponsiveDialogClose\n          variant=\"ghost\"\n          size=\"xs\"\n          className=\"absolute right-3 top-3 w-[var(--control-h-xs)] px-0 opacity-70 hover:opacity-100\"\n        >\n          <svg viewBox=\"0 0 16 16\" className=\"size-4\" aria-hidden=\"true\" fill=\"none\">\n            <path d=\"M4 4 12 12M12 4 4 12\" stroke=\"currentColor\" strokeWidth=\"1.4\" strokeLinecap=\"round\" />\n          </svg>\n          <span className=\"sr-only\">Close</span>\n        </ResponsiveDialogClose>\n      ) : null}\n    </DrawerContent>\n  );\n}\n\nexport function ResponsiveDialogHeader(props: ComponentProps<typeof DialogHeader>) {\n  const isMobile = useResponsiveDialogContext();\n  return isMobile ? <DrawerHeader {...props} /> : <DialogHeader {...props} />;\n}\n\nexport function ResponsiveDialogFooter(props: ComponentProps<typeof DialogFooter>) {\n  const isMobile = useResponsiveDialogContext();\n  return isMobile ? <DrawerFooter {...props} /> : <DialogFooter {...props} />;\n}\n\nexport function ResponsiveDialogTitle(props: ComponentProps<typeof DialogTitle>) {\n  const isMobile = useResponsiveDialogContext();\n  return isMobile ? <DrawerTitle {...props} /> : <DialogTitle {...props} />;\n}\n\nexport function ResponsiveDialogDescription(props: ComponentProps<typeof DialogDescription>) {\n  const isMobile = useResponsiveDialogContext();\n  return isMobile ? <DrawerDescription {...props} /> : <DialogDescription {...props} />;\n}\n"
    }
  ],
  "meta": {}
}
