{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "responsive-preview-shell",
  "title": "Responsive Preview Shell",
  "description": "A responsive preview utility with viewport controls and a smooth carousel with soft blurred edges.",
  "dependencies": [
    "lucide-react",
    "motion"
  ],
  "registryDependencies": [
    "button",
    "https://ui.corr.sh/r/carousel.json",
    "toggle-group"
  ],
  "files": [
    {
      "path": "registry/corr/components/responsive-preview-shell.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport {\n  LaptopIcon,\n  MonitorIcon,\n  SmartphoneIcon,\n  TabletIcon,\n} from \"lucide-react\"\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\"\n\nimport {\n  Carousel,\n  CarouselContent,\n} from \"./carousel\"\nimport { ToggleGroup, ToggleGroupItem } from \"@/components/ui/toggle-group\"\nimport { cn } from \"@/lib/utils\"\n\nexport type ResponsivePreviewViewport = {\n  value: string\n  label: string\n  width: number\n  height: number\n  icon?: React.ReactNode\n}\n\nexport type ResponsivePreviewShellRenderProps = {\n  viewport: ResponsivePreviewViewport\n  viewports: ResponsivePreviewViewport[]\n  isDesktop: boolean\n  isTablet: boolean\n  isMobile: boolean\n}\n\nconst defaultViewports: ResponsivePreviewViewport[] = [\n  {\n    value: \"desktop\",\n    label: \"Desktop\",\n    width: 960,\n    height: 520,\n    icon: <MonitorIcon className=\"size-4\" />,\n  },\n  {\n    value: \"tablet\",\n    label: \"Tablet\",\n    width: 720,\n    height: 520,\n    icon: <TabletIcon className=\"size-4\" />,\n  },\n  {\n    value: \"mobile\",\n    label: \"Mobile\",\n    width: 390,\n    height: 640,\n    icon: <SmartphoneIcon className=\"size-4\" />,\n  },\n]\n\nexport function ResponsivePreviewShell({\n  children,\n  title,\n  description,\n  defaultViewport = \"desktop\",\n  viewports = defaultViewports,\n  className,\n}: {\n  children:\n    | React.ReactNode\n    | ((props: ResponsivePreviewShellRenderProps) => React.ReactNode)\n  title?: string\n  description?: string\n  defaultViewport?: \"desktop\" | \"tablet\" | \"mobile\" | string\n  viewports?: ResponsivePreviewViewport[]\n  className?: string\n}) {\n  const [viewport, setViewport] = React.useState(defaultViewport)\n  const reduceMotion = useReducedMotion()\n  const activeViewport =\n    viewports.find((item) => item.value === viewport) ?? viewports[0]\n  const renderProps = {\n    viewport: activeViewport,\n    viewports,\n    isDesktop: activeViewport.value === \"desktop\",\n    isTablet: activeViewport.value === \"tablet\",\n    isMobile: activeViewport.value === \"mobile\",\n  }\n  const content =\n    typeof children === \"function\" ? children(renderProps) : children\n\n  return (\n    <div className={cn(\"rounded-md border bg-card\", className)}>\n      <div className=\"flex flex-wrap items-start justify-between gap-3 border-b p-3\">\n        <div className=\"min-w-0\">\n          {title ? <h3 className=\"text-sm font-medium\">{title}</h3> : null}\n          {description ? (\n            <p className=\"mt-1 text-xs leading-5 text-muted-foreground\">\n              {description}\n            </p>\n          ) : null}\n        </div>\n        <ToggleGroup\n          type=\"single\"\n          value={activeViewport.value}\n          onValueChange={(value) => value && setViewport(value)}\n          className=\"rounded-md border bg-background p-0.5\"\n        >\n          {viewports.map((item) => (\n            <ToggleGroupItem\n              key={item.value}\n              value={item.value}\n              size=\"sm\"\n              className=\"h-8 px-2\"\n            >\n              {item.icon ?? <LaptopIcon className=\"size-4\" />}\n              <span className=\"sr-only\">{item.label}</span>\n            </ToggleGroupItem>\n          ))}\n        </ToggleGroup>\n      </div>\n      <div className=\"overflow-x-auto p-4\">\n        <AnimatePresence mode=\"wait\" initial={false}>\n          <motion.div\n            key={activeViewport.value}\n            initial={{\n              opacity: 0,\n              scale: reduceMotion ? 1 : 0.985,\n            }}\n            animate={{ opacity: 1, scale: 1 }}\n            exit={{\n              opacity: 0,\n              scale: reduceMotion ? 1 : 0.985,\n            }}\n            transition={{ duration: reduceMotion ? 0 : 0.18 }}\n            className=\"mx-auto overflow-hidden rounded-md border bg-background shadow-sm\"\n            style={{\n              width: activeViewport.width,\n              maxWidth: \"100%\",\n              height: activeViewport.height,\n            }}\n          >\n            {content}\n          </motion.div>\n        </AnimatePresence>\n      </div>\n    </div>\n  )\n}\n\nexport function ResponsivePreviewCarousel({\n  children,\n  title,\n  description,\n  className,\n}: {\n  children: React.ReactNode\n  title?: string\n  description?: string\n  className?: string\n}) {\n  return (\n    <Carousel title={title} description={description} className={className}>\n      <CarouselContent>{children}</CarouselContent>\n    </Carousel>\n  )\n}\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:component"
}