{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "chat",
  "type": "registry:component",
  "title": "Chat",
  "description": "A complete chat component that composes chat-message and chat-input and wires to /api/chat.",
  "dependencies": [
    "ai",
    "@ai-sdk/react",
    "@ai-sdk/openai",
    "@radix-ui/react-select",
    "class-variance-authority",
    "lucide-react"
  ],
  "registryDependencies": [
    "accordion"
  ],
  "files": [
    {
      "path": "registry/new-york/routes/chat/route.ts",
      "content": "import { openai } from \"@ai-sdk/openai\";\nimport { convertToModelMessages, streamText, UIMessage, stepCountIs, smoothStream } from \"ai\";\n\nexport async function POST(req: Request) {\n  const { messages }: { messages: UIMessage[] } = await req.json();\n\n  const result = streamText({\n    model: openai(\"gpt-5\"),\n    messages: convertToModelMessages(messages),\n    providerOptions: {\n      openai: {\n        reasoningSummary: \"auto\",\n      },\n    },\n    stopWhen: stepCountIs(100),\n    experimental_transform: smoothStream(),\n  });\n\n  return result.toUIMessageStreamResponse();\n}\n",
      "type": "registry:component",
      "target": "app/api/chat/route.ts"
    },
    {
      "path": "registry/new-york/blocks/chat/chat.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport ChatMessage from \"@/registry/new-york/blocks/chat-message/chat-message\";\nimport ChatInput from \"@/registry/new-york/blocks/chat-input/chat-input\";\nimport { useChat } from \"@ai-sdk/react\";\nimport { DefaultChatTransport, UIMessage } from \"ai\";\nimport { cn } from \"@/lib/utils\";\nimport { AlertTriangle, Loader } from \"lucide-react\";\n\nexport default function Chat({\n  defaultModel = \"gpt-5-nano\",\n  className,\n}: {\n  defaultModel?: string;\n  className?: string;\n}) {\n  const { messages, sendMessage, status, error, stop } = useChat({\n    transport: new DefaultChatTransport({\n      api: \"/api/chat\",\n    }),\n  });\n\n  const [input, setInput] = React.useState<string>(\"\");\n  const models = React.useMemo(\n    () => [\n      { id: \"gpt-5\", name: \"GPT-5\", description: \"Reasoning-capable, efficient\" },\n      { id: \"gpt-5-mini\", name: \"GPT-5 mini\", description: \"Fast and affordable\" },\n      { id: \"gpt-5-nano\", name: \"GPT-5 nano\", description: \"Reasoning-capable, efficient\" },\n    ],\n    []\n  );\n  const [model, setModel] = React.useState<string>(defaultModel || models[0]?.id);\n\n  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {\n    e.preventDefault();\n    if (!input.trim()) return;\n    sendMessage({ text: input.trim() }, { body: { model } });\n    setInput(\"\");\n  };\n\n  const handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n    setInput(e.target.value);\n  };\n\n  return (\n    <div className={cn(\"relative flex flex-col\", className)}>\n      <div className=\"flex flex-col gap-2 flex-1 min-h-0 overflow-y-auto px-2\">\n        {messages.map((m: UIMessage) => (\n          <ChatMessage key={m.id} message={m} />\n        ))}\n        <div className=\"min-h-32\"></div>\n      </div>\n\n      {status === \"streaming\" ||\n        (status === \"submitted\" && (\n          <div className=\"text-sm text-muted-foreground\">\n            <Loader className=\"size-4 animate-spin\" />\n          </div>\n        ))}\n\n      {status === \"error\" && error && (\n        <div className=\"text-destructive text-sm flex items-center gap-2 px-4 py-2 rounded-md bg-destructive/10\">\n          <AlertTriangle className=\"size-4\" />\n          {error.message}\n        </div>\n      )}\n\n      <ChatInput\n        title=\"\"\n        placeholder=\"Ask anything...\"\n        models={models}\n        allowFileUpload={false}\n        loading={status === \"streaming\"}\n        handleSubmit={handleSubmit}\n        handleInputChange={handleInputChange}\n        input={input}\n        stop={stop}\n        className=\"absolute bottom-0\"\n        model={model}\n        onModelChange={setModel}\n      />\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/chat/chat.tsx"
    },
    {
      "path": "registry/new-york/blocks/chat-message/chat-message.tsx",
      "content": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\nimport { VariantProps, cva } from \"class-variance-authority\";\nimport Markdown from \"@/registry/new-york/blocks/markdown/markdown\";\nimport React from \"react\";\nimport { ToolUIPart, UIMessage } from \"ai\";\nimport ChatReasoning from \"@/registry/new-york/blocks/chat-reasoning/chat-reasoning\";\nimport ChatTool from \"@/registry/new-york/blocks/chat-tool/chat-tool\";\n\nconst userMessageVariants = cva(\"flex flex-col gap-2\", {\n  variants: {\n    variant: {\n      raised:\n        \"bg-gradient-to-b from-primary to-primary/80 border border-primary text-primary-foreground shadow-lg shadow-shade max-w-2xs ml-auto rounded-xl px-4 py-2 font-medium\",\n      title: \"font-semibold tracking-tight text-3xl mt-4 border-b border-primary/30 pb-1\",\n      default: \"bg-primary/20 max-w-2xs ml-auto rounded-xl px-4 py-2\",\n    },\n  },\n});\nconst assistantMessageVariants = cva(\"flex flex-col gap-2\", {\n  variants: {\n    variant: {\n      raised:\n        \"bg-gradient-to-b from-muted to-muted/50 rounded-xl px-4 py-2 border shadow-md shadow-shade mr-8\",\n      paragraph: \"\",\n      default: \"bg-muted rounded-xl px-4 py-2 mr-8\",\n    },\n  },\n});\n\n// Helper function to render a single message part\nconst renderMessagePart = (part: any, key: string | number) => {\n  if (part.type.includes(\"tool\")) {\n    return (\n      <ChatTool\n        toolMessagePart={part as ToolUIPart}\n        className=\"my-1 border-none px-0 py-0 shadow-none text-muted-foreground\"\n      />\n    );\n  } else if (part.type === \"text\") {\n    return <Markdown key={key}>{part.text}</Markdown>;\n  } else if (part.type === \"reasoning\") {\n    return (\n      <Markdown key={key} className=\"text-sm text-muted-foreground\">\n        {part.text}\n      </Markdown>\n    );\n  }\n  return <div key={key}>{part.type}</div>;\n};\n\nexport default function ChatMessage({\n  message,\n  className,\n  userMessageVariant = \"default\",\n  assistantMessageVariant = \"default\",\n}: {\n  message: UIMessage;\n  className?: string;\n  userMessageVariant?: VariantProps<typeof userMessageVariants>[\"variant\"];\n  assistantMessageVariant?: VariantProps<typeof assistantMessageVariants>[\"variant\"];\n}) {\n  if (message.role === \"user\") {\n    return (\n      <div\n        className={cn(userMessageVariants({ variant: userMessageVariant }), className)}\n        role=\"user\"\n      >\n        {message.parts.map((part) => part.type === \"text\" && part.text).join(\"\")}\n      </div>\n    );\n  }\n\n  const firstTextIndex = message.parts.findIndex((part) => part.type === \"text\");\n  const hasTextPart = firstTextIndex !== -1;\n\n  const shouldShowAccordion = firstTextIndex !== 0;\n  const accordionDefaultValue = !hasTextPart ? \"reasoning\" : null;\n  const partsInAccordion = shouldShowAccordion ? message.parts.slice(0, firstTextIndex) : [];\n  const partsAfter = hasTextPart ? message.parts.slice(firstTextIndex) : [];\n\n  return (\n    <div className={cn(\"flex items-start gap-3\", className)}>\n      <div\n        className={cn(\n          \"flex flex-col gap-1 relative\",\n          assistantMessageVariants({ variant: assistantMessageVariant })\n        )}\n      >\n        {shouldShowAccordion && (\n          <ChatReasoning\n            renderMessagePart={renderMessagePart}\n            partsInAccordion={partsInAccordion}\n            defaultValue={accordionDefaultValue ?? undefined}\n          />\n        )}\n        {partsAfter.map((part, index) => renderMessagePart(part, firstTextIndex + index))}\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/chat/chat-message.tsx"
    },
    {
      "path": "registry/new-york/blocks/chat-input/chat-input.tsx",
      "content": "\"use client\";\n\nimport { Button } from \"@/registry/new-york/blocks/button/button\";\nimport { SendIcon, SquareIcon, UploadIcon } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\nimport {\n  Select,\n  SelectContent,\n  SelectItem,\n  SelectTrigger,\n  SelectValue,\n} from \"@/registry/new-york/blocks/select/select\";\nimport { Textarea } from \"@/registry/new-york/blocks/textarea/textarea\";\n\nexport default function ChatInput({\n  title,\n  placeholder = \"Ask anything...\",\n  models,\n  allowFileUpload,\n  loading,\n  handleSubmit,\n  handleInputChange,\n  input = \"\",\n  className,\n  model = \"\",\n  onModelChange,\n  stop,\n}: {\n  handleSubmit?: (e: React.FormEvent<HTMLFormElement>) => void;\n  handleInputChange?: (e: React.ChangeEvent<HTMLTextAreaElement>) => void;\n  input?: string;\n  className?: string;\n  model: string;\n  onModelChange?: (model: string) => void;\n  title?: string;\n  placeholder?: string;\n  models: { id: string; name: string; description: string }[];\n  allowFileUpload?: boolean;\n  loading?: boolean;\n  stop?: () => void;\n}) {\n  return (\n    <form\n      onSubmit={handleSubmit}\n      className={cn(\"w-full relative flex flex-col gap-4 items-center\", className)}\n    >\n      {title && <h2 className=\"text-5xl font-medium tracking-tight\">{title}</h2>}\n      <Textarea\n        name=\"prompt\"\n        value={input}\n        onChange={handleInputChange}\n        disabled={loading}\n        autoComplete=\"off\"\n        placeholder={placeholder}\n        className=\"w-full pb-20 pt-4 px-4 rounded-xl text-md bg-background disabled:opacity-100 disabled:cursor-not-allowed disabled:bg-background\"\n        onKeyDown={(e) => {\n          if (e.key === \"Enter\" && !e.shiftKey && !e.nativeEvent.isComposing) {\n            e.preventDefault();\n            e.currentTarget.form?.requestSubmit();\n          }\n        }}\n      />\n      <Button\n        type={loading ? \"button\" : \"submit\"}\n        onClick={() => {\n          if (stop) {\n            stop();\n          }\n        }}\n        disabled={!stop && loading}\n        variant=\"fancy\"\n        size=\"icon\"\n        className=\"absolute bottom-2 right-2\"\n      >\n        {loading ? <SquareIcon className=\"w-4 h-4\" /> : <SendIcon className=\"w-4 h-4\" />}\n      </Button>\n      {onModelChange && models && (\n        <div className=\"flex items-center gap-2 absolute bottom-0 left-0\">\n          <Select value={model} onValueChange={(value) => onModelChange(value)}>\n            <SelectTrigger className=\"w-[200px] shadow-none pl-4 hover:bg-transparent hover:text-foreground focus-visible:ring-0 border-none bg-transparent text-xs text-muted-foreground dark:bg-transparent\">\n              <SelectValue>\n                {models.find((m) => m.id === model)?.name || \"Select a model\"}\n              </SelectValue>\n            </SelectTrigger>\n            <SelectContent className=\"rounded-xl shadow-shade\">\n              {models.map((model) => (\n                <SelectItem\n                  key={model.id}\n                  value={model.id}\n                  className=\"rounded-lg focus:bg-primary/5\"\n                >\n                  <div className=\"flex flex-col\">\n                    <span>{model.name}</span>\n                    <span className=\"text-xs text-muted-foreground\">{model.description}</span>\n                  </div>\n                </SelectItem>\n              ))}\n            </SelectContent>\n          </Select>\n          {allowFileUpload && (\n            <Button variant=\"outline\" size=\"icon\">\n              <UploadIcon className=\"w-4 h-4\" />\n            </Button>\n          )}\n        </div>\n      )}\n    </form>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/chat/chat-input.tsx"
    },
    {
      "path": "registry/new-york/blocks/chat-tool/chat-tool.tsx",
      "content": "import {\n  Accordion,\n  AccordionContent,\n  AccordionItem,\n  AccordionTrigger,\n} from \"@/components/ui/accordion\";\nimport { DynamicToolUIPart, ToolUIPart } from \"ai\";\nimport { cn } from \"@/lib/utils\";\nimport { Wrench, Loader2, Check, AlertCircle } from \"lucide-react\";\n\n// Helper function to get state information\nfunction getStateInfo(state: string) {\n  switch (state) {\n    case \"input-streaming\":\n      return {\n        icon: Wrench,\n        label: \"Using \",\n        color: \"text-muted-foreground\",\n      };\n    case \"input-available\":\n      return {\n        icon: Loader2,\n        label: \"Using \",\n        color: \"text-muted-foreground\",\n      };\n    case \"output-available\":\n      return {\n        icon: Check,\n        label: \"Used \",\n        color: \"text-success\",\n      };\n    case \"output-error\":\n      return {\n        icon: AlertCircle,\n        label: \"Failed to use\",\n        color: \"text-destructive\",\n      };\n    default:\n      return {\n        icon: Wrench,\n        label: \"Using\",\n        color: \"text-muted-foreground\",\n      };\n  }\n}\n\n// Helper function to safely render unknown values\nfunction renderValue(value: unknown): React.ReactNode {\n  if (typeof value === \"string\") {\n    return value;\n  }\n  return JSON.stringify(value, null, 2);\n}\n\nexport default function ChatTool({\n  toolMessagePart,\n  className,\n}: {\n  toolMessagePart: ToolUIPart | DynamicToolUIPart;\n  className?: string;\n}) {\n  const toolName =\n    toolMessagePart.type === \"dynamic-tool\"\n      ? toolMessagePart.toolName\n      : toolMessagePart.type.replace(\"tool-\", \"\");\n\n  const stateInfo = getStateInfo(toolMessagePart.state);\n  const StateIcon = stateInfo.icon;\n\n  return (\n    <Accordion type=\"single\" collapsible className=\"w-full\">\n      <AccordionItem\n        value=\"tool\"\n        className={cn(\n          \"px-2 border rounded-xl hover:no-underline py-2 w-full last:border-b shadow-xs\",\n          className\n        )}\n      >\n        <AccordionTrigger className={cn(\"py-0 hover:no-underline hover:opacity-70 transition-all\")}>\n          <span className=\"flex items-center gap-2\">\n            <StateIcon\n              className={cn(\n                \"w-4 h-4\",\n                stateInfo.color,\n                toolMessagePart.state === \"input-available\" && \"animate-spin\"\n              )}\n            />\n            <span className=\"text-sm\">\n              {stateInfo.label} {toolName}\n            </span>\n          </span>\n        </AccordionTrigger>\n        <AccordionContent className=\"pb-0\">\n          <div className=\"flex flex-col gap-3 w-full pt-2\">\n            {/* Error Section - show for failed executions */}\n            {toolMessagePart.state === \"output-error\" && toolMessagePart.errorText && (\n              <div className=\"bg-destructive/5 border rounded-md p-2 text-sm overflow-x-auto whitespace-pre-wrap text-destructive w-full\">\n                {toolMessagePart.errorText}\n              </div>\n            )}\n            {/* Input Section - always show if available */}\n            {\"input\" in toolMessagePart &&\n            toolMessagePart.input !== undefined &&\n            toolMessagePart.input !== null ? (\n              <div className=\"w-full\">\n                <div className=\"text-xs font-semibold text-muted-foreground mb-1\">Input</div>\n                <pre className=\"bg-muted rounded-md p-2 text-sm overflow-x-auto whitespace-pre-wrap w-full\">\n                  {renderValue(toolMessagePart.input)}\n                </pre>\n              </div>\n            ) : (\n              <div className=\"text-xs text-muted-foreground\">No input</div>\n            )}\n\n            {/* Output Section - show for successful completion */}\n            {toolMessagePart.state === \"output-available\" &&\n              \"output\" in toolMessagePart &&\n              toolMessagePart.output !== undefined &&\n              toolMessagePart.output !== null && (\n                <div className=\"w-full\">\n                  <div className=\"text-xs font-semibold text-muted-foreground mb-1\">Output</div>\n                  <pre className=\"bg-muted rounded-md p-2 text-sm overflow-x-auto whitespace-pre-wrap w-full\">\n                    {renderValue(toolMessagePart.output)}\n                  </pre>\n                </div>\n              )}\n          </div>\n        </AccordionContent>\n      </AccordionItem>\n    </Accordion>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/chat/chat-tool.tsx"
    },
    {
      "path": "registry/new-york/blocks/chat-reasoning/chat-reasoning.tsx",
      "content": "import {\n  Accordion,\n  AccordionContent,\n  AccordionItem,\n  AccordionTrigger,\n} from \"@/components/ui/accordion\";\nimport { cn } from \"@/lib/utils\";\nimport { UIDataTypes, UIMessagePart, UITools } from \"ai\";\nimport React from \"react\";\n\nexport default function ChatReasoning({\n  partsInAccordion,\n  defaultValue,\n  renderMessagePart,\n  className,\n}: {\n  partsInAccordion: UIMessagePart<UIDataTypes, UITools>[];\n  defaultValue?: string;\n  renderMessagePart: (\n    part: UIMessagePart<UIDataTypes, UITools>,\n    key: string | number\n  ) => React.ReactNode;\n  className?: string;\n}) {\n  const [value, setValue] = React.useState<string | undefined>(defaultValue);\n\n  React.useEffect(() => {\n    setValue(defaultValue);\n  }, [defaultValue]);\n\n  return (\n    <Accordion\n      type=\"single\"\n      collapsible\n      value={value}\n      onValueChange={setValue}\n      className={cn(\"w-full\", className)}\n    >\n      <AccordionItem value=\"reasoning\" className=\"w-full\">\n        <AccordionTrigger className=\"text-md text-muted-foreground hover:no-underline hover:opacity-70 py-2 w-full\">\n          {defaultValue === \"reasoning\" ? \"Reasoning...\" : `Done reasoning.`}\n        </AccordionTrigger>\n        <AccordionContent className=\"p-0 -mt-1\">\n          <div className=\"flex flex-col gap-0\">\n            {partsInAccordion.map(\n              (part, index) =>\n                part.type !== \"step-start\" && (\n                  <div key={index} className=\"flex gap-2 pl-2\">\n                    <div className=\"flex flex-col items-center gap-1 pt-2 -mb-1\">\n                      <div className=\"w-2 h-2 bg-muted-foreground/50 rounded-full\" />\n                      <div\n                        className={cn(\n                          \"w-0.5 min-h-0 flex-1 bg-border rounded-full\",\n                          index === partsInAccordion.length - 1 &&\n                            \"bg-gradient-to-b from-border to-transparent\"\n                        )}\n                      />\n                    </div>\n                    <div className=\"flex-1\">{renderMessagePart(part, `accordion-${index}`)}</div>\n                  </div>\n                )\n            )}\n          </div>\n        </AccordionContent>\n      </AccordionItem>\n    </Accordion>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/chat/chat-reasoning.tsx"
    },
    {
      "path": "registry/new-york/blocks/markdown/markdown.tsx",
      "content": "import ReactMarkdown, { Components } from \"react-markdown\";\nimport remarkGfm from \"remark-gfm\";\nimport { cn } from \"@/lib/utils\";\nimport { CodeBlock } from \"@/registry/new-york/blocks/code-block/code-block\";\nimport { Button } from \"@/registry/new-york/blocks/button/button\";\n\nconst components: Components = {\n  // Text components\n  p: ({ children }) => <p className=\"text-base mb-3 last:mb-0\">{children}</p>,\n  h1: ({ children }) => (\n    <h1 className=\"text-4xl font-semibold tracking-tight mb-4 mt-2\">{children}</h1>\n  ),\n  h2: ({ children }) => (\n    <h2 className=\"text-3xl font-semibold tracking-tight mt-4 mb-2 border-b border-border pb-2\">\n      {children}\n    </h2>\n  ),\n  h3: ({ children }) => (\n    <h3 className=\"text-2xl font-semibold tracking-tight mt-4 mb-2\">{children}</h3>\n  ),\n  h4: ({ children }) => (\n    <h4 className=\"text-xl font-semibold tracking-tight mt-3 mb-2\">{children}</h4>\n  ),\n  h5: ({ children }) => (\n    <h5 className=\"text-lg font-semibold tracking-tight mt-2 mb-1\">{children}</h5>\n  ),\n  h6: ({ children }) => (\n    <h6 className=\"text-base font-semibold tracking-tight mt-2 mb-1\">{children}</h6>\n  ),\n\n  // Lists\n  ul: ({ children }) => (\n    <ul className=\"text-base my-2 pl-6 list-disc marker:text-primary/70\">{children}</ul>\n  ),\n  ol: ({ children }) => <ol className=\"text-base my-2 pl-6 list-decimal\">{children}</ol>,\n  li: ({ children }) => <li className=\"my-0.5\">{children}</li>,\n\n  // Inline formatting\n  strong: ({ children }) => <strong className=\"font-bold\">{children}</strong>,\n  em: ({ children }) => <em className=\"italic\">{children}</em>,\n  del: ({ children }) => <del className=\"line-through\">{children}</del>,\n\n  // Block elements\n  blockquote: ({ children }) => (\n    <blockquote className=\"pl-4 border-l-4 border-primary/20 my-2 italic text-primary/70\">\n      {children}\n    </blockquote>\n  ),\n  hr: () => <hr className=\"my-4 border-t border-border\" />,\n\n  // Tables\n  table: ({ children }) => (\n    <div className=\"overflow-x-auto my-4\">\n      <table className=\"min-w-full divide-y divide-border border border-border\">{children}</table>\n    </div>\n  ),\n  thead: ({ children }) => <thead className=\"bg-muted/50\">{children}</thead>,\n  tbody: ({ children }) => <tbody className=\"divide-y divide-border\">{children}</tbody>,\n  tr: ({ children }) => <tr>{children}</tr>,\n  th: ({ children }) => (\n    <th className=\"px-3 py-2 text-left text-xs font-medium text-muted-foreground uppercase tracking-wider\">\n      {children}\n    </th>\n  ),\n  td: ({ children }) => <td className=\"px-3 py-2 whitespace-nowrap text-sm\">{children}</td>,\n\n  // Links and images\n  a: ({ children, href, title }) => (\n    <Button\n      variant=\"link\"\n      size=\"sm\"\n      className=\"text-primary hover:underline p-0 m-0\"\n      title={title}\n      onClick={() => {\n        if (href) {\n          window.open(href, \"_blank\", \"noopener noreferrer\");\n        }\n      }}\n      disabled={!href}\n      asChild\n    >\n      {children}\n    </Button>\n  ),\n  img: ({ src, alt, title }) => (\n    <div className=\"flex flex-col items-center w-fit\">\n      <img\n        src={src || \"\"}\n        alt={alt || \"\"}\n        title={title || alt || \"\"}\n        className=\"max-w-sm h-auto my-2 rounded-xl\"\n      />\n      <p className=\"text-sm text-center text-muted-foreground\">{alt}</p>\n    </div>\n  ),\n\n  // Code blocks and inline code\n  code: ({ className, children }) => {\n    const match = /language-(\\w+)/.exec(className || \"\");\n    const isInline = !match;\n    return !isInline && match ? (\n      <CodeBlock code={String(children).replace(/\\n$/, \"\")} language={match[1]} />\n    ) : (\n      <code className=\"bg-muted px-1.5 py-0.5 rounded-md text-sm text-primary font-mono\">\n        {children}\n      </code>\n    );\n  },\n  pre: ({ children }) => <>{children}</>,\n};\n\nexport default function Markdown({\n  children,\n  className,\n}: {\n  children: string;\n  className?: string;\n}) {\n  return (\n    <div className={cn(\"w-full\", className)}>\n      <ReactMarkdown remarkPlugins={[remarkGfm]} components={components}>\n        {children}\n      </ReactMarkdown>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/ui/markdown.tsx"
    },
    {
      "path": "registry/new-york/blocks/code-block/code-block.tsx",
      "content": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\nimport React, { useEffect, useState } from \"react\";\nimport { Button } from \"@/registry/new-york/blocks/button/button\";\nimport { Check, Copy } from \"lucide-react\";\nimport { Prism as SyntaxHighlighter } from \"react-syntax-highlighter\";\nimport { oneLight, a11yDark as oneDark } from \"react-syntax-highlighter/dist/esm/styles/prism\";\nimport { cva } from \"class-variance-authority\";\nimport { useTheme } from \"next-themes\";\n\nconst customSyntaxTheme = {\n  ...oneLight,\n  'pre[class*=\"language-\"]': {\n    ...oneLight['pre[class*=\"language-\"]'],\n    background: \"hsl(var(--muted))\",\n    borderRadius: \"0.5rem\",\n    fontFamily: \"Geist Mono, monospace\",\n    textShadow: \"none\",\n    padding: 0,\n    margin: 0,\n  },\n  'code[class*=\"language-\"]': {\n    ...oneLight['code[class*=\"language-\"]'],\n    background: \"none\",\n    fontFamily: \"Geist Mono, monospace\",\n    textShadow: \"none\",\n    fontSize: \"13px\",\n    padding: 0,\n  },\n};\n\nconst customDarkSyntaxTheme = {\n  ...oneDark,\n  'pre[class*=\"language-\"]': {\n    ...oneDark['pre[class*=\"language-\"]'],\n    background: \"hsl(var(--muted))\",\n    borderRadius: \"0.5rem\",\n    fontFamily: \"Geist Mono, monospace\",\n    textShadow: \"none\",\n    padding: 0,\n    margin: 0,\n  },\n  'code[class*=\"language-\"]': {\n    ...oneDark['code[class*=\"language-\"]'],\n    background: \"none\",\n    fontFamily: \"Geist Mono, monospace\",\n    textShadow: \"none\",\n    fontSize: \"13px\",\n    padding: 0,\n  },\n};\n\nconst codeBlockVariants = cva(\"text-card-foreground rounded-xl p-4 flex flex-col gap-2\", {\n  variants: {\n    variant: {\n      flat: \"bg-muted\",\n      default: \"border border-border bg-card\",\n    },\n  },\n  defaultVariants: {\n    variant: \"default\",\n  },\n});\n\nexport type CodeBlockProps = {\n  code: string;\n  language?: string;\n  theme?: string;\n  className?: string;\n  title?: string;\n  children?: React.ReactNode;\n  variant?: \"default\" | \"flat\";\n} & React.HTMLProps<HTMLDivElement>;\n\nexport function CodeBlock({\n  code,\n  language = \"tsx\",\n  theme = \"github-light\",\n  className,\n  title,\n  children,\n  variant = \"default\",\n  ...props\n}: CodeBlockProps) {\n  const { theme: themeName } = useTheme();\n  const codeClassNames = cn(\"w-full overflow-x-auto text-[13px] font-mono\");\n  const [copied, setCopied] = useState(false);\n  return (\n    <div className={cn(\"relative group\", codeBlockVariants({ variant }), className)} {...props}>\n      <Button\n        onClick={() => {\n          navigator.clipboard.writeText(String(code));\n          setCopied(true);\n          setTimeout(() => {\n            setCopied(false);\n          }, 1000);\n        }}\n        variant=\"ghost\"\n        size=\"icon\"\n        className=\"absolute right-2 top-2 focus-visible:ring-0 text-muted-foreground hover:bg-muted active:bg-muted\"\n        aria-label={copied ? \"Copied\" : \"Copy to clipboard\"}\n      >\n        <span className=\"sr-only\">{copied ? \"Copied\" : \"Copy\"}</span>\n        <Copy\n          className={`size-4 transition-all duration-300 ${copied ? \"scale-0\" : \"scale-100\"}`}\n        />\n        <Check\n          className={`absolute inset-0 m-auto size-4 transition-all duration-300 text-success ${\n            copied ? \"scale-100\" : \"scale-0\"\n          }`}\n        />\n      </Button>\n      {title && <h3 className=\"text-sm text-muted-foreground tracking-tight font-mono\">{title}</h3>}\n      <SyntaxHighlighter\n        language={language}\n        style={themeName === \"dark\" ? customDarkSyntaxTheme : customSyntaxTheme}\n        PreTag=\"div\"\n        className={codeClassNames}\n      >\n        {code}\n      </SyntaxHighlighter>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/ui/code-block.tsx"
    },
    {
      "path": "registry/new-york/blocks/button/button.tsx",
      "content": "import * as React from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst buttonVariants = cva(\n  \"inline-flex items-center justify-center gap-1 whitespace-nowrap rounded-xl text-md font-medium disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive duration-200 hover:duration-75 transition-all\",\n  {\n    variants: {\n      variant: {\n        default:\n          \"border border-primary bg-primary/70 bg-linear-to-t from-primary to-primary/30 px-4 py-2 font-medium text-primary-foreground shadow-md inset-shadow-[0px_1px_0px_1px] inset-shadow-white/30 transition-all duration-75 hover:bg-primary/60 active:translate-y-px active:inset-shadow-black/10 dark:bg-primary dark:from-primary dark:to-primary/80 dark:hover:bg-primary/90\",\n        fancy:\n          \"border border-primary bg-primary/30 bg-radial-[at_50%_25%] from-primary/40 to-primary text-primary-foreground shadow-md inset-shadow-sm inset-shadow-white/50 hover:bg-white hover:shadow-lg hover:inset-shadow-white active:bg-primary/30 active:shadow-none active:inset-shadow-primary/80  hover:-translate-y-px active:translate-y-px\",\n        destructive:\n          \"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60\",\n        outline:\n          \"border shadow-lg hover:shadow-none shadow-shade bg-transparent text-primary hover:border-transparent hover:bg-primary/10 active:bg-primary/30\",\n        secondary:\n          \"border border-transparent bg-primary/10 text-primary hover:border-primary/50 hover:bg-transparent  active:border-transparent active:border-primary active:ring-1 active:scale-95\",\n        ghost:\n          \"bg-transparent text-primary hover:border-transparent hover:bg-primary/10 active:bg-primary/30\",\n        link: \"text-foreground underline decoration-primary underline-offset-2 hover:underline-offset-2 active:decoration-4 hover:opacity-70 hover:decoration-2 active:text-foreground\",\n      },\n      size: {\n        default: \"px-4 py-2\",\n        xs: \"px-2 py-1.5 rounded-lg [&_svg:not([class*='size-'])]:size-3 text-xs\",\n        sm: \"px-3 py-1.5 text-sm rounded-lg\",\n        lg: \"px-5 py-2 text-lg\",\n        xl: \"px-6 py-3 [&_svg:not([class*='size-'])]:size-5 text-xl\",\n        icon: \"size-8 rounded-lg [&_svg:not([class*='size-'])]:size-4\",\n        iconSm: \"size-6 rounded-md [&_svg:not([class*='size-'])]:size-3\",\n        iconLg: \"size-10 rounded-lg [&_svg:not([class*='size-'])]:size-5\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n      size: \"default\",\n    },\n  }\n);\n\nfunction Button({\n  className,\n  variant,\n  size,\n  asChild = false,\n  ...props\n}: React.ComponentProps<\"button\"> &\n  VariantProps<typeof buttonVariants> & {\n    asChild?: boolean;\n  }) {\n  const Comp = asChild ? Slot : \"button\";\n\n  return (\n    <Comp\n      data-slot=\"button\"\n      className={cn(buttonVariants({ variant, size, className }))}\n      {...props}\n    />\n  );\n}\n\nexport { Button, buttonVariants };\n",
      "type": "registry:component",
      "target": "components/ui/button.tsx"
    },
    {
      "path": "registry/new-york/blocks/select/select.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport * as SelectPrimitive from \"@radix-ui/react-select\";\nimport { CheckIcon, ChevronDownIcon, ChevronUpIcon } from \"lucide-react\";\n\nimport { cn } from \"@/lib/utils\";\n\nfunction Select({ ...props }: React.ComponentProps<typeof SelectPrimitive.Root>) {\n  return <SelectPrimitive.Root data-slot=\"select\" {...props} />;\n}\n\nfunction SelectGroup({ ...props }: React.ComponentProps<typeof SelectPrimitive.Group>) {\n  return <SelectPrimitive.Group data-slot=\"select-group\" {...props} />;\n}\n\nfunction SelectValue({ ...props }: React.ComponentProps<typeof SelectPrimitive.Value>) {\n  return <SelectPrimitive.Value data-slot=\"select-value\" {...props} />;\n}\n\nfunction SelectTrigger({\n  className,\n  size = \"default\",\n  children,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {\n  size?: \"sm\" | \"default\";\n}) {\n  return (\n    <SelectPrimitive.Trigger\n      data-slot=\"select-trigger\"\n      data-size={size}\n      className={cn(\n        \"border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-primary focus-visible:ring-primary/30 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex items-center justify-between gap-2 rounded-xl border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-md shadow-shade  transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 data-[size=sm]:rounded-lg *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 w-full\",\n        \"hover:shadow-none hover:bg-muted hover:border-border/0 transition-all duration-150 ease-out hover:duration-75\",\n        className\n      )}\n      {...props}\n    >\n      {children}\n      <SelectPrimitive.Icon asChild>\n        <ChevronDownIcon className=\"size-4 opacity-50\" />\n      </SelectPrimitive.Icon>\n    </SelectPrimitive.Trigger>\n  );\n}\n\nfunction SelectContent({\n  className,\n  children,\n  position = \"popper\",\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Content>) {\n  return (\n    <SelectPrimitive.Portal>\n      <SelectPrimitive.Content\n        data-slot=\"select-content\"\n        className={cn(\n          \"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2  relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-xl border shadow-lg shadow-shade duration-150 w-full\",\n          position === \"popper\" &&\n            \"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1\",\n          className\n        )}\n        position={position}\n        {...props}\n      >\n        <SelectScrollUpButton />\n        <SelectPrimitive.Viewport\n          className={cn(\n            \"p-1\",\n            position === \"popper\" &&\n              \"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1\"\n          )}\n        >\n          {children}\n        </SelectPrimitive.Viewport>\n        <SelectScrollDownButton />\n      </SelectPrimitive.Content>\n    </SelectPrimitive.Portal>\n  );\n}\n\nfunction SelectLabel({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.Label>) {\n  return (\n    <SelectPrimitive.Label\n      data-slot=\"select-label\"\n      className={cn(\"text-muted-foreground px-2 py-1.5 text-xs\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction SelectItem({\n  className,\n  children,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Item>) {\n  return (\n    <SelectPrimitive.Item\n      data-slot=\"select-item\"\n      className={cn(\n        \"focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-lg py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2\",\n        \"transition-all duration-150 ease-out focus:duration-75\",\n        className\n      )}\n      {...props}\n    >\n      <span className=\"absolute right-2 flex size-3.5 items-center justify-center\">\n        <SelectPrimitive.ItemIndicator>\n          <CheckIcon className=\"size-4\" />\n        </SelectPrimitive.ItemIndicator>\n      </span>\n      <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n    </SelectPrimitive.Item>\n  );\n}\n\nfunction SelectSeparator({\n  className,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.Separator>) {\n  return (\n    <SelectPrimitive.Separator\n      data-slot=\"select-separator\"\n      className={cn(\"bg-border pointer-events-none -mx-1 my-1 h-px\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction SelectScrollUpButton({\n  className,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {\n  return (\n    <SelectPrimitive.ScrollUpButton\n      data-slot=\"select-scroll-up-button\"\n      className={cn(\"flex cursor-default items-center justify-center py-1\", className)}\n      {...props}\n    >\n      <ChevronUpIcon className=\"size-4\" />\n    </SelectPrimitive.ScrollUpButton>\n  );\n}\n\nfunction SelectScrollDownButton({\n  className,\n  ...props\n}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {\n  return (\n    <SelectPrimitive.ScrollDownButton\n      data-slot=\"select-scroll-down-button\"\n      className={cn(\"flex cursor-default items-center justify-center py-1\", className)}\n      {...props}\n    >\n      <ChevronDownIcon className=\"size-4\" />\n    </SelectPrimitive.ScrollDownButton>\n  );\n}\n\nexport {\n  Select,\n  SelectContent,\n  SelectGroup,\n  SelectItem,\n  SelectLabel,\n  SelectScrollDownButton,\n  SelectScrollUpButton,\n  SelectSeparator,\n  SelectTrigger,\n  SelectValue,\n};\n",
      "type": "registry:component",
      "target": "components/ui/select.tsx"
    },
    {
      "path": "registry/new-york/blocks/textarea/textarea.tsx",
      "content": "import * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nfunction Textarea({\n  className,\n  showHandle = true,\n  ...props\n}: React.ComponentProps<\"textarea\"> & { showHandle?: boolean }) {\n  return (\n    <textarea\n      data-slot=\"textarea\"\n      className={cn(\n        \"border-input placeholder:text-muted-foreground focus-visible:border-primary focus-visible:ring-primary/30 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-xl border bg-transparent p-3 text-base shadow-md shadow-shade transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm\",\n        showHandle ? \"resize-y\" : \"resize-none\",\n        \"hover:shadow-none hover:bg-foreground/5 hover:border-border/0 transition-all duration-150 ease-out hover:duration-75\",\n        className\n      )}\n      {...props}\n    />\n  );\n}\n\nexport { Textarea };\n",
      "type": "registry:component",
      "target": "components/ui/textarea.tsx"
    }
  ]
}