{
  "title": "Block Viewer",
  "description": "React context managing block variant navigation, theme toggling, and clipboard actions.",
  "name": "mcp-block-viewer",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "button",
    "dropdown-menu",
    "label",
    "textarea",
    "tooltip"
  ],
  "type": "registry:component",
  "files": [
    {
      "path": "components/ui/mcp/block-viewer/index.tsx",
      "type": "registry:component",
      "content": "import {\n    CheckIcon,\n    ChevronLeftIcon,\n    ChevronRightIcon,\n    CopyIcon,\n    InfoIcon,\n    MoonIcon,\n    PencilIcon,\n    SunIcon,\n} from \"lucide-react\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger } from \"@/components/ui/dropdown-menu\";\nimport { Label } from \"@/components/ui/label\";\nimport { Textarea } from \"@/components/ui/textarea\";\nimport { Tooltip, TooltipContent, TooltipTrigger } from \"@/components/ui/tooltip\";\n\nimport { type BlockViewerProps, BlockViewerProvider, useBlockViewer } from \"./block-viewer-context\";\n\nexport const BlockViewer = (props: BlockViewerProps) => {\n    return (\n        <BlockViewerProvider {...props}>\n            <BlockWindow />\n        </BlockViewerProvider>\n    );\n};\n\nconst BlockWindow = () => {\n    const { title, selectedVariant } = useBlockViewer();\n\n    return (\n        <div className=\"flex min-h-[85vh] flex-col p-8 xl:p-16\">\n            <div className=\"fixed inset-0 -z-1 bg-[radial-gradient(#7f7f7f_1px,transparent_1px)] bg-size-[16px_16px] opacity-15\"></div>\n\n            <div className=\"flex flex-col items-center justify-center\">\n                <p className=\"text-2xl font-semibold\">{title}</p>\n                <p className=\"text-muted-foreground text-sm\">Select a variant to add a component</p>\n            </div>\n            <div className=\"mt-8 flex grow flex-col justify-center\">\n                <div className=\"relative flex h-full min-h-36 w-full items-center justify-center overflow-hidden p-2\">\n                    {selectedVariant}\n                </div>\n            </div>\n            <div className=\"fixed inset-x-0 bottom-6 flex items-center justify-center xl:bottom-8\">\n                <BlockTool />\n            </div>\n        </div>\n    );\n};\n\nconst BlockTool = () => {\n    const { next, variants, theme, updateTheme, previous, goTo, selectedIndex, showPickedTooltip, onPicked } =\n        useBlockViewer();\n\n    return (\n        <div>\n            <div className=\"bg-card flex items-center rounded-md border py-2 ps-4 pe-2\">\n                <p className=\"font-medium\">PaceUI</p>\n                <div className=\"bg-border ms-3 me-1 h-6 w-px\"></div>\n                <div className=\"flex items-center justify-center gap-0.5\">\n                    <Button\n                        variant=\"ghost\"\n                        size=\"icon\"\n                        className=\"cursor-pointer\"\n                        aria-label=\"Previous variant\"\n                        onClick={previous}>\n                        <ChevronLeftIcon className=\"size-4\" />\n                    </Button>\n                    {variants.map((_, index) => (\n                        <Button\n                            key={index}\n                            onClick={() => goTo(index)}\n                            className=\"cursor-pointer shadow-none\"\n                            variant={selectedIndex == index ? \"outline\" : \"ghost\"}\n                            size=\"icon\">\n                            {index + 1}\n                        </Button>\n                    ))}\n                    <Button\n                        variant=\"ghost\"\n                        size=\"icon\"\n                        className=\"cursor-pointer\"\n                        aria-label=\"Next variant\"\n                        onClick={next}>\n                        <ChevronRightIcon className=\"size-4\" />\n                    </Button>\n                </div>\n                <div className=\"bg-border mx-1 h-6 w-px\"></div>\n                <div className=\"flex items-center\">\n                    <Button\n                        onClick={() => updateTheme(theme === \"light\" ? \"dark\" : \"light\")}\n                        size=\"icon\"\n                        variant=\"ghost\"\n                        aria-label=\"Toggle theme\">\n                        {theme === \"light\" ? <MoonIcon /> : <SunIcon />}\n                    </Button>\n                    <EditVariantMenu />\n                    <Tooltip open={showPickedTooltip}>\n                        <TooltipTrigger\n                            render={\n                                <Button variant=\"secondary\" onClick={onPicked}>\n                                    Pick This\n                                </Button>\n                            }\n                        />\n                        <TooltipContent>Copied prompt! Paste into your agent to resume</TooltipContent>\n                    </Tooltip>\n                </div>\n            </div>\n            <div className=\"not-hover:text-muted-foreground mt-1.5 flex items-center justify-center gap-1.5 text-xs transition-all\">\n                <InfoIcon className=\"size-3.5\" />\n                <p>Paste the suggested prompt into your IDE where the agent is running</p>\n            </div>\n        </div>\n    );\n};\n\nconst EditVariantMenu = () => {\n    const { selectedIndex, variantReview, setVariantReview, copied, onCopy } = useBlockViewer();\n    return (\n        <DropdownMenu>\n            <DropdownMenuTrigger\n                render={\n                    <Button\n                        variant=\"ghost\"\n                        size=\"icon\"\n                        className=\"cursor-pointer shadow-none\"\n                        aria-label=\"Edit variant\"\n                        onClick={() => console.log(\"edit\")}>\n                        <PencilIcon />\n                    </Button>\n                }\n            />\n            <DropdownMenuContent side=\"top\" align=\"center\" className=\"w-72 p-0 shadow-xs\">\n                <div className=\"p-4\">\n                    <Label htmlFor=\"variant-review\" className=\"text-sm font-medium\">\n                        Describe the changes for Variant {selectedIndex + 1}?\n                    </Label>\n                    <Textarea\n                        id=\"variant-review\"\n                        className=\"mt-3 h-12 shadow-none placeholder:text-xs\"\n                        value={variantReview}\n                        placeholder=\"Make it more concise, or use a friendlier tone\"\n                        onChange={(e) => setVariantReview(e.target.value)}\n                        onKeyDown={(e) => e.stopPropagation()}\n                    />\n                    <div className=\"mt-3 flex items-center gap-2 text-sm\">\n                        <Button\n                            size=\"xs\"\n                            variant=\"outline\"\n                            className=\"shadow-none\"\n                            onClick={onCopy}\n                            disabled={copied || !variantReview.length}>\n                            {copied ? <CheckIcon /> : <CopyIcon />}\n                            Copy\n                        </Button>\n                        <p className=\"text-muted-foreground text-xs\">prompt and paste to agent</p>\n                    </div>\n                </div>\n            </DropdownMenuContent>\n        </DropdownMenu>\n    );\n};\n"
    },
    {
      "path": "components/ui/mcp/block-viewer/block-viewer-context.tsx",
      "type": "registry:ui",
      "content": "import { type ReactNode, createContext, useContext, useState } from \"react\";\n\nexport type BlockViewerProps = {\n    title: string;\n    variants: ReactNode[];\n};\n\nconst useHook = (props: BlockViewerProps) => {\n    const { variants } = props;\n    const [selectedIndex, setSelectedIndex] = useState(0);\n    const [variantReview, setVariantReview] = useState(\"\");\n    const [copied, setCopied] = useState(false);\n    const [showPickedTooltip, setShowPickedTooltip] = useState(false);\n    const [theme, setTheme] = useState<\"light\" | \"dark\">(\"light\");\n\n    const previous = () => {\n        setSelectedIndex((prevIndex) => (prevIndex - 1 + variants.length) % variants.length);\n    };\n\n    const next = () => {\n        setSelectedIndex((prevIndex) => (prevIndex + 1) % variants.length);\n    };\n\n    const goTo = (index: number) => {\n        setSelectedIndex(index);\n    };\n\n    const updateTheme = (theme: \"light\" | \"dark\") => {\n        const html = document.documentElement;\n        [...html.style].filter((p) => p.startsWith(\"--\")).forEach((p) => html.style.removeProperty(p));\n        if (theme === \"light\") {\n            html.classList.remove(\"dark\");\n            html.setAttribute(\"data-theme\", \"light\");\n        } else {\n            html.classList.add(\"dark\");\n            html.setAttribute(\"data-theme\", \"dark\");\n        }\n        setTheme(theme);\n    };\n\n    const onPicked = () => {\n        setShowPickedTooltip(true);\n        navigator.clipboard.writeText(`Approve variant ${selectedIndex + 1}`);\n        setTimeout(() => setShowPickedTooltip(false), 4000);\n    };\n\n    const onCopy = () => {\n        const text = variantReview.trim();\n        if (text.length == 0) return;\n\n        navigator.clipboard.writeText(`${text}\\nat: variant ${selectedIndex + 1}`);\n        setCopied(true);\n        setVariantReview(\"\");\n        setTimeout(() => setCopied(false), 2000);\n    };\n\n    return {\n        previous,\n        next,\n        goTo,\n        copied,\n        onCopy,\n        onPicked,\n        theme,\n        updateTheme,\n        showPickedTooltip,\n        selectedIndex,\n        variantReview,\n        setVariantReview,\n        variants,\n        title: props.title,\n        selectedVariant: variants[selectedIndex],\n    };\n};\n\nconst BlockViewerContext = createContext({} as ReturnType<typeof useHook>);\n\nexport const BlockViewerProvider = ({ children, ...props }: { children: ReactNode } & BlockViewerProps) => {\n    return <BlockViewerContext value={useHook(props)}>{children}</BlockViewerContext>;\n};\n\nexport const useBlockViewer = () => {\n    return useContext(BlockViewerContext);\n};\n"
    }
  ],
  "mcp": {
    "description": "Provides refined UI interactions and accessible controls. React context managing block variant navigation, theme toggling, and clipboard actions. Relies on lucide-react, button, dropdown-menu, label, textarea, tooltip. Optimal for building reusable interface elements and user input flows.",
    "tags": [
      "component",
      "mcp"
    ]
  }
}