{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "morphing-dialog",
  "title": "Morphing Dialog",
  "description": "A fluid card-to-modal transition pattern. Combines Base UI's accessible dialog primitives with Framer Motion's shared layout animations for a seamless expansion effect. Inspired by Linear.",
  "dependencies": [
    "lucide-react",
    "motion"
  ],
  "registryDependencies": [
    "@lumi-ui/button",
    "@lumi-ui/dialog",
    "@lumi-ui/scroll-area"
  ],
  "files": [
    {
      "path": "registry/components/morphing-dialog.tsx",
      "content": "\"use client\";\n\nimport type { DialogRootActions } from \"@base-ui/react/dialog\";\nimport { PlusIcon, X } from \"lucide-react\";\nimport { AnimatePresence, LayoutGroup, motion } from \"motion/react\";\nimport { useRef, useState } from \"react\";\nimport { Button } from \"@/registry/ui/button\";\nimport {\n  Dialog,\n  DialogBackdrop,\n  DialogClose,\n  DialogPopup,\n  DialogPortal,\n  DialogTitle,\n  DialogViewport,\n} from \"@/registry/ui/dialog\";\nimport { ScrollArea } from \"@/registry/ui/scroll-area\";\n\nexport function MorphingDialog() {\n  const [isOpen, setIsOpen] = useState(false);\n  const [activeItem, setActiveItem] = useState<(typeof ITEMS)[0] | null>(null);\n\n  const actionsRef = useRef<DialogRootActions>({\n    close: () => {},\n    unmount: () => {},\n  });\n\n  const handleOpen = (item: (typeof ITEMS)[0]) => {\n    setActiveItem(item);\n    setIsOpen(true);\n  };\n\n  const handleClose = (open: boolean) => {\n    setIsOpen(open);\n  };\n\n  return (\n    <div>\n      <LayoutGroup>\n        <ScrollArea\n          className=\"w-screen whitespace-nowrap container\"\n          noScrollBar\n        >\n          <div className=\"flex gap-2 md:gap-6 lg:gap-10 mx-auto\">\n            {ITEMS.map((item) => (\n              <motion.button\n                className=\"relative group flex flex-col cursor-pointer bg-muted hover:bg-muted/80 transition-colors flex-1 size-64 lg:size-80 rounded focus-visible:outline focus-visible:outline-ring focus-visible:ring-4 focus-visible:ring-ring/10\"\n                key={item.id}\n                layoutId={`card-container-${item.id}`}\n                onClick={() => handleOpen(item)}\n                style={{\n                  opacity: activeItem?.id === item.id && isOpen ? 0 : 1,\n                  pointerEvents:\n                    activeItem?.id === item.id && isOpen ? \"none\" : \"auto\",\n                }}\n              >\n                <div className=\"relative h-48 w-full overflow-hidden rounded rounded-b-none\">\n                  <motion.div\n                    className=\"w-full h-full\"\n                    layoutId={`image-container-${item.id}`}\n                  >\n                    <img\n                      alt={item.title}\n                      className=\"h-full w-full object-cover dark:brightness-20 dark:grayscale-25\"\n                      height={500}\n                      src={item.image}\n                      width={500}\n                    />\n                  </motion.div>\n                </div>\n                <div className=\"flex flex-1 p-4 justify-between items-center rounded rounded-t-none\">\n                  <motion.h3\n                    className=\"text-lg font-semibold\"\n                    layoutId={`title-${item.id}`}\n                    transition={{ duration: 0.2 }}\n                  >\n                    {item.title}\n                  </motion.h3>\n\n                  <PlusIcon className=\"group-hover:text-foreground text-muted-foreground transition-all\" />\n                </div>\n              </motion.button>\n            ))}\n          </div>\n        </ScrollArea>\n        <Dialog\n          actionsRef={actionsRef}\n          onOpenChange={handleClose}\n          open={isOpen}\n        >\n          <AnimatePresence mode=\"popLayout\">\n            {isOpen && activeItem && (\n              <DialogPortal keepMounted>\n                <DialogBackdrop />\n                <DialogViewport\n                  className=\"grid place-items-center p-4 pt-32\"\n                  hidden={false}\n                >\n                  <DialogPopup\n                    className=\"relative w-full max-w-4xl flex flex-col overflow-hidden rounded\"\n                    hidden={false}\n                    render={\n                      <motion.div\n                        layoutId={`card-container-${activeItem.id}`}\n                        onLayoutAnimationComplete={() => {\n                          if (!isOpen) {\n                            actionsRef.current?.unmount();\n                            setTimeout(() => setActiveItem(null), 50);\n                          }\n                        }}\n                      />\n                    }\n                  >\n                    <ScrollArea className=\"h-[calc(100vh-4rem)]\" noScrollBar>\n                      <motion.div\n                        animate={{ opacity: 1 }}\n                        className=\"flex flex-col h-full pb-[10vh]\"\n                        exit={{ opacity: 0 }}\n                        initial={{ opacity: 0 }}\n                        transition={{\n                          duration: 0.15,\n                        }}\n                      >\n                        <div className=\"relative h-64 sm:h-96 w-full shrink-0 overflow-hidden\">\n                          <motion.div\n                            className=\"w-full h-full\"\n                            layoutId={`image-container-${activeItem.id}`}\n                          >\n                            <img\n                              alt={activeItem.title}\n                              className=\"h-full w-full object-cover dark:brightness-20 dark:grayscale-25\"\n                              height={500}\n                              src={activeItem.image}\n                              width={500}\n                            />\n                          </motion.div>\n                        </div>\n\n                        <div className=\"flex flex-col p-4 sm:p-8 justify-start text-left space-y-6\">\n                          <DialogTitle\n                            className=\"text-3xl sm:text-4xl md:text-5xl xl:text-6xl font-bold\"\n                            render={\n                              <motion.h2 layoutId={`title-${activeItem.id}`}>\n                                {activeItem.title}\n                              </motion.h2>\n                            }\n                          />\n                          <motion.div\n                            animate={{ opacity: 1, y: 0 }}\n                            initial={{ opacity: 0, y: 10 }}\n                            transition={{ delay: 0.2 }}\n                          >\n                            {activeItem.content}\n                          </motion.div>\n                        </div>\n\n                        <DialogClose\n                          className=\"absolute right-4 top-4 z-20\"\n                          render={\n                            <Button\n                              className=\"rounded-full shadow-lg\"\n                              size=\"icon\"\n                              variant=\"secondary\"\n                            >\n                              <X size={16} />\n                            </Button>\n                          }\n                        />\n                      </motion.div>\n                    </ScrollArea>\n                  </DialogPopup>\n                </DialogViewport>\n              </DialogPortal>\n            )}\n          </AnimatePresence>\n        </Dialog>\n      </LayoutGroup>\n    </div>\n  );\n}\n\ntype CardItem = {\n  id: string;\n  title: string;\n  image: string;\n  content: React.ReactNode;\n};\n\nconst ITEMS: CardItem[] = [\n  {\n    content: (\n      <div className=\"space-y-4 text-muted-foreground leading-relaxed\">\n        <p>\n          Modern development is human + AI. We optimized Lumi UI's structure so\n          that AI assistants generate correct, idiomatic code on the first\n          attempt.\n        </p>\n        <ul className=\"list-disc pl-5 space-y-2\">\n          <li>\n            <strong className=\"text-foreground\">Flat Semantic Exports:</strong>{\" \"}\n            Every component is accessible at the root level, making it easier\n            for AI to infer usage and reducing context tokens.\n          </li>\n          <li>\n            <strong className=\"text-foreground\">\n              Composites as Living Examples:\n            </strong>{\" \"}\n            Our composite components serve as executable documentation.\n          </li>\n          <li>\n            <strong className=\"text-foreground\">Immutable Logic Blocks:</strong>{\" \"}\n            Primitives are stable building blocks. You compose them rather than\n            modifying core logic.\n          </li>\n        </ul>\n        <div className=\"pt-8\">\n          <h4 className=\"text-foreground font-semibold mb-4 text-lg\">\n            Deep Dive: Optimization\n          </h4>\n          <div className=\"grid gap-4\">\n            {Array.from({ length: 3 }).map((_, i) => (\n              <div className=\"bg-muted/50 rounded-lg p-4 space-y-2\" key={i}>\n                <div className=\"h-4 w-1/3 bg-muted rounded\" />\n                <div className=\"h-20 w-full bg-muted rounded\" />\n              </div>\n            ))}\n          </div>\n        </div>\n      </div>\n    ),\n    id: \"card-1\",\n    image: \"/images/placeholder.svg\",\n    title: \"Discoverable\",\n  },\n  {\n    content: (\n      <div className=\"space-y-4 text-muted-foreground leading-relaxed\">\n        <p>\n          Base UI provides the behavioral foundation, but we provide the visual\n          consistency. Every component adapts to your needs following a unified\n          language.\n        </p>\n        <ul className=\"list-disc pl-5 space-y-2\">\n          <li>\n            <strong className=\"text-foreground\">The Utility Pattern:</strong> We\n            use utility classes to provide consistent styling across all\n            components.\n          </li>\n          <li>\n            <strong className=\"text-foreground\">Global Animation:</strong> All\n            interactive elements use globally configured animation utilities for\n            cohesive transitions.\n          </li>\n          <li>\n            <strong className=\"text-foreground\">Hit-Test Philosophy:</strong> We\n            use pseudo-elements to separate visual highlights from interactive\n            containers, creating forgiving, clickable areas.\n          </li>\n        </ul>\n        <div className=\"pt-8\">\n          <h4 className=\"text-foreground font-semibold mb-4 text-lg\">\n            Design System Specs\n          </h4>\n          <div className=\"grid gap-4\">\n            <div className=\"aspect-video bg-muted rounded-lg w-full flex items-center justify-center text-muted-foreground\">\n              Animation Curve Visualization\n            </div>\n            <div className=\"aspect-video bg-muted rounded-lg w-full flex items-center justify-center text-muted-foreground\">\n              Spacing Scale\n            </div>\n          </div>\n        </div>\n      </div>\n    ),\n    id: \"card-2\",\n    image: \"/images/placeholder.svg\",\n    title: \"Predictable\",\n  },\n  {\n    content: (\n      <div className=\"space-y-4 text-muted-foreground leading-relaxed\">\n        <p>\n          We refuse the false dichotomy between speed and control. Our Dual\n          Layer Architecture accommodates both prototyping and polishing modes.\n        </p>\n        <ul className=\"list-disc pl-5 space-y-2\">\n          <li>\n            <strong className=\"text-foreground\">Composites = Velocity:</strong>{\" \"}\n            Pre-assembled components that combine structure, styling, and logic\n            for MVPs and standard use cases.\n          </li>\n          <li>\n            <strong className=\"text-foreground\">Primitives = Control:</strong>{\" \"}\n            Thin wrappers around Base UI that enforce zero visual layout, giving\n            you complete control over DOM structure.\n          </li>\n          <li>\n            <strong className=\"text-foreground\">Mix and Match:</strong> Use\n            composites for speed and primitive blocks for unique custom designs\n            in the same project.\n          </li>\n        </ul>\n        <div className=\"pt-8\">\n          <h4 className=\"text-foreground font-semibold mb-4 text-lg\">\n            Component Architecture\n          </h4>\n          <div className=\"flex flex-col gap-4\">\n            <div className=\"h-32 bg-muted rounded-lg border-2 border-dashed border-muted-foreground/20 flex items-center justify-center\">\n              Composite Layer\n            </div>\n            <div className=\"h-10 text-center text-muted-foreground text-sm\">\n              ↓ Adapts to ↓\n            </div>\n            <div className=\"h-32 bg-muted rounded-lg border-2 border-dashed border-muted-foreground/20 flex items-center justify-center\">\n              Primitive Layer\n            </div>\n          </div>\n        </div>\n      </div>\n    ),\n    id: \"card-3\",\n    image: \"/images/placeholder.svg\",\n    title: \"Composable\",\n  },\n];\n",
      "type": "registry:component"
    }
  ],
  "meta": {
    "iframeHeight": 1000
  },
  "categories": [
    "layout-navigation"
  ],
  "type": "registry:component"
}