{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "ai-snippet",
  "title": "AI: Snippet",
  "description": "A compact copyable command or text snippet with prefix and overflow handling.",
  "dependencies": [
    "@untitledui/icons@^0.0.23"
  ],
  "registryDependencies": [
    "@nx-ui/utils",
    "@nx-ui/input-group"
  ],
  "files": [
    {
      "path": "components/ai/snippet.tsx",
      "content": "// Ported from vercel/ai-elements@6a9d5b1822ffb10bba4bd97175f01edd7d8651cd.\n\"use client\";\n\nimport {\n  InputGroup,\n  InputGroupAddon,\n  InputGroupButton,\n  InputGroupInput,\n  InputGroupText,\n} from \"@/components/ui/input-group\";\nimport { cn } from \"@/lib/utils\";\nimport { Check as CheckIcon, Copy01 as CopyIcon } from \"@untitledui/icons\";\nimport type { ComponentProps } from \"react\";\nimport {\n  createContext,\n  useCallback,\n  useContext,\n  useEffect,\n  useMemo,\n  useRef,\n  useState,\n} from \"react\";\n\ninterface SnippetContextType {\n  code: string;\n}\n\nconst SnippetContext = createContext<SnippetContextType>({\n  code: \"\",\n});\n\nexport type SnippetProps = ComponentProps<typeof InputGroup> & {\n  code: string;\n};\n\nexport const Snippet = ({\n  code,\n  className,\n  children,\n  ...props\n}: SnippetProps) => {\n  const contextValue = useMemo(() => ({ code }), [code]);\n\n  return (\n    <SnippetContext.Provider value={contextValue}>\n      <InputGroup className={cn(\"font-mono\", className)} {...props}>\n        {children}\n      </InputGroup>\n    </SnippetContext.Provider>\n  );\n};\n\nexport type SnippetAddonProps = ComponentProps<typeof InputGroupAddon>;\n\nexport const SnippetAddon = (props: SnippetAddonProps) => (\n  <InputGroupAddon {...props} />\n);\n\nexport type SnippetTextProps = ComponentProps<typeof InputGroupText>;\n\nexport const SnippetText = ({ className, ...props }: SnippetTextProps) => (\n  <InputGroupText\n    className={cn(\"pl-2 font-normal text-muted-foreground\", className)}\n    {...props}\n  />\n);\n\nexport type SnippetInputProps = Omit<\n  ComponentProps<typeof InputGroupInput>,\n  \"readOnly\" | \"value\"\n>;\n\nexport const SnippetInput = ({ className, ...props }: SnippetInputProps) => {\n  const { code } = useContext(SnippetContext);\n\n  return (\n    <InputGroupInput\n      className={cn(\"text-foreground\", className)}\n      readOnly\n      value={code}\n      {...props}\n    />\n  );\n};\n\nexport type SnippetCopyButtonProps = ComponentProps<typeof InputGroupButton> & {\n  onCopy?: () => void;\n  onError?: (error: Error) => void;\n  timeout?: number;\n};\n\nexport const SnippetCopyButton = ({\n  onCopy,\n  onError,\n  timeout = 2000,\n  children,\n  className,\n  \"aria-label\": ariaLabel,\n  ...props\n}: SnippetCopyButtonProps) => {\n  const [isCopied, setIsCopied] = useState(false);\n  const timeoutRef = useRef<number>(0);\n  const { code } = useContext(SnippetContext);\n\n  const copyToClipboard = useCallback(async () => {\n    if (typeof window === \"undefined\" || !navigator?.clipboard?.writeText) {\n      onError?.(new Error(\"Clipboard API not available\"));\n      return;\n    }\n\n    try {\n      if (!isCopied) {\n        await navigator.clipboard.writeText(code);\n        setIsCopied(true);\n        onCopy?.();\n        timeoutRef.current = window.setTimeout(\n          () => setIsCopied(false),\n          timeout\n        );\n      }\n    } catch (error) {\n      onError?.(error as Error);\n    }\n  }, [code, onCopy, onError, timeout, isCopied]);\n\n  useEffect(\n    () => () => {\n      window.clearTimeout(timeoutRef.current);\n    },\n    []\n  );\n\n  const Icon = isCopied ? CheckIcon : CopyIcon;\n\n  return (\n    <InputGroupButton\n      className={className}\n      onClick={copyToClipboard}\n      size=\"icon-sm\"\n      title=\"Copy\"\n      {...props}\n      aria-label={ariaLabel ?? \"Copy snippet\"}\n    >\n      {children ?? <Icon className=\"size-3.5\" size={14} />}\n    </InputGroupButton>\n  );\n};\n",
      "type": "registry:ui",
      "target": "components/ai/snippet.tsx"
    }
  ],
  "type": "registry:ui"
}