{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "code-editor",
  "type": "registry:component",
  "title": "Code Editor",
  "description": "Lightweight code editor component",
  "registryDependencies": [],
  "files": [
    {
      "path": "components/chatcn/ai/code-editor.tsx",
      "content": "\"use client\";\nimport React, { createContext, useContext, useRef, useState } from \"react\";\nimport Editor, { EditorProps, Monaco } from \"@monaco-editor/react\";\nimport type { editor } from \"monaco-editor\";\nimport { cn } from \"@/lib/utils\";\nimport { motion } from \"framer-motion\";\nimport {\n  Select,\n  SelectContent,\n  SelectItem,\n  SelectTrigger,\n} from \"@/components/ui/select\";\nimport {\n  Tooltip,\n  TooltipContent,\n  TooltipProvider,\n  TooltipTrigger,\n} from \"@/components/ui/tooltip\";\n\nexport const ACTION_ANIMATION = {\n  whileHover: { backgroundColor: \"rgba(255, 255, 255, 0.1)\" },\n  whileTap: { backgroundColor: \"rgba(255, 255, 255, 0.15)\" },\n  transition: { duration: 0.15 },\n};\n\nexport const SPINNER_ANIMATION = {\n  animate: { rotate: 360 },\n  transition: { duration: 1.5, repeat: Infinity, ease: \"linear\" as const },\n};\n\nexport const PULSE_ANIMATION = {\n  animate: { opacity: [1, 0.5, 1] },\n  transition: { duration: 2, repeat: Infinity },\n};\n\nexport type Language = { value: string; label: string; icon?: string };\n\nconst DEVICON = \"https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons\";\nexport const DEFAULT_LANGUAGES: Language[] = [\n  {\n    value: \"python\",\n    label: \"Python\",\n    icon: `${DEVICON}/python/python-original.svg`,\n  },\n  {\n    value: \"javascript\",\n    label: \"JavaScript\",\n    icon: `${DEVICON}/javascript/javascript-original.svg`,\n  },\n  {\n    value: \"typescript\",\n    label: \"TypeScript\",\n    icon: `${DEVICON}/typescript/typescript-original.svg`,\n  },\n  { value: \"java\", label: \"Java\", icon: `${DEVICON}/java/java-original.svg` },\n  {\n    value: \"cpp\",\n    label: \"C++\",\n    icon: `${DEVICON}/cplusplus/cplusplus-original.svg`,\n  },\n  { value: \"c\", label: \"C\", icon: `${DEVICON}/c/c-original.svg` },\n  { value: \"go\", label: \"Go\", icon: `${DEVICON}/go/go-original.svg` },\n  { value: \"rust\", label: \"Rust\", icon: `${DEVICON}/rust/rust-original.svg` },\n  {\n    value: \"swift\",\n    label: \"Swift\",\n    icon: `${DEVICON}/swift/swift-original.svg`,\n  },\n  {\n    value: \"kotlin\",\n    label: \"Kotlin\",\n    icon: `${DEVICON}/kotlin/kotlin-original.svg`,\n  },\n];\n\ntype CodeEditorContextType = {\n  value: string;\n  language: string;\n  theme: string;\n  languages: Language[];\n  cursorLine: number;\n  cursorColumn: number;\n  disabled?: boolean;\n  setValue: (v: string) => void;\n  setLanguage: (l: string) => void;\n  setCursorPosition: (line: number, col: number) => void;\n  editorRef: React.RefObject<editor.IStandaloneCodeEditor | null>;\n};\n\nconst CodeEditorContext = createContext<CodeEditorContextType | null>(null);\n\nexport function useCodeEditor() {\n  const ctx = useContext(CodeEditorContext);\n  if (!ctx) throw Error(\"Must be used within CodeEditor\");\n  return ctx;\n}\n\nexport type CodeEditorHeaderProps = {\n  children?: React.ReactNode;\n  className?: string;\n  showLanguageSelector?: boolean;\n};\n\nexport function CodeEditorHeader({\n  children,\n  className,\n  showLanguageSelector = true,\n}: CodeEditorHeaderProps) {\n  const { language, setLanguage, languages } = useCodeEditor();\n  const lang = languages.find((l) => l.value === language);\n\n  return (\n    <div\n      className={cn(\n        \"flex flex-wrap items-center justify-between gap-2 px-3 py-2 bg-secondary/50 border-b border-border\",\n        className\n      )}\n    >\n      {showLanguageSelector && (\n        <Select value={language} onValueChange={setLanguage}>\n          <SelectTrigger className=\"w-30 sm:w-40 h-8 text-xs sm:text-sm font-medium bg-background border-border hover:bg-accent transition-colors\">\n            <span className=\"flex items-center gap-2\">\n              {lang?.icon && <img src={lang.icon} alt=\"\" className=\"w-4 h-4\" />}\n              <span>{lang?.label || language}</span>\n            </span>\n          </SelectTrigger>\n          <SelectContent>\n            {languages.map((l) => (\n              <SelectItem key={l.value} value={l.value} className=\"text-sm\">\n                <span className=\"flex items-center gap-2\">\n                  {l.icon && <img src={l.icon} alt=\"\" className=\"w-4 h-4\" />}\n                  {l.label}\n                </span>\n              </SelectItem>\n            ))}\n          </SelectContent>\n        </Select>\n      )}\n      <div className=\"flex flex-wrap items-center gap-1\">{children}</div>\n    </div>\n  );\n}\n\nexport type CodeEditorActionsProps = React.HTMLAttributes<HTMLDivElement>;\n\nexport function CodeEditorActions({\n  children,\n  className,\n  ...props\n}: CodeEditorActionsProps) {\n  return (\n    <div className={cn(\"flex items-center gap-1\", className)} {...props}>\n      {children}\n    </div>\n  );\n}\n\nexport type CodeEditorActionProps = {\n  tooltip: React.ReactNode;\n  children: React.ReactNode;\n  className?: string;\n  side?: \"top\" | \"bottom\" | \"left\" | \"right\";\n  animate?: boolean;\n} & React.ComponentProps<typeof Tooltip>;\n\nexport function CodeEditorAction({\n  tooltip,\n  children,\n  className,\n  side = \"top\",\n  animate = true,\n  ...props\n}: CodeEditorActionProps) {\n  const { disabled } = useCodeEditor();\n  return (\n    <TooltipProvider>\n      <Tooltip {...props}>\n        <TooltipTrigger\n          asChild\n          disabled={disabled}\n          onClick={(e) => e.stopPropagation()}\n        >\n          {animate ? (\n            <motion.div {...ACTION_ANIMATION}>{children}</motion.div>\n          ) : (\n            children\n          )}\n        </TooltipTrigger>\n        <TooltipContent side={side} className={className}>\n          {tooltip}\n        </TooltipContent>\n      </Tooltip>\n    </TooltipProvider>\n  );\n}\n\nexport function CodeEditorDivider() {\n  return <div className=\"w-px h-5 bg-border mx-1\" />;\n}\n\nexport type CodeEditorAreaProps = {\n  loader?: React.ReactNode;\n  className?: string;\n  height?: string | number;\n  width?: string | number;\n} & Omit<EditorProps, \"value\" | \"onChange\" | \"language\" | \"theme\">;\n\nexport function CodeEditorArea({\n  loader,\n  className,\n  height = \"400px\",\n  width = \"100%\",\n  ...props\n}: CodeEditorAreaProps) {\n  const {\n    disabled,\n    value,\n    setValue,\n    language,\n    theme,\n    editorRef,\n    setCursorPosition,\n  } = useCodeEditor();\n\n  const handleMount = (\n    editor: editor.IStandaloneCodeEditor,\n    monaco: Monaco\n  ) => {\n    editorRef.current = editor;\n    editor.onDidChangeCursorPosition((e) =>\n      setCursorPosition(e.position.lineNumber, e.position.column)\n    );\n    monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({\n      noSemanticValidation: true,\n      noSyntaxValidation: true,\n    });\n    monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({\n      noSemanticValidation: true,\n      noSyntaxValidation: true,\n    });\n    monaco.editor.defineTheme(\"premium-dark\", {\n      base: \"vs-dark\",\n      inherit: true,\n      rules: [\n        { token: \"comment\", foreground: \"6A9955\", fontStyle: \"italic\" },\n        { token: \"keyword\", foreground: \"C586C0\" },\n        { token: \"string\", foreground: \"CE9178\" },\n        { token: \"number\", foreground: \"B5CEA8\" },\n        { token: \"function\", foreground: \"DCDCAA\" },\n        { token: \"variable\", foreground: \"9CDCFE\" },\n        { token: \"type\", foreground: \"4EC9B0\" },\n      ],\n      colors: {\n        \"editor.background\": \"#0D0D0D\",\n        \"editor.foreground\": \"#D4D4D4\",\n        \"editor.lineHighlightBackground\": \"#1A1A1A\",\n        \"editor.selectionBackground\": \"#264F78\",\n        \"editorCursor.foreground\": \"#10B981\",\n        \"editorLineNumber.foreground\": \"#4A4A4A\",\n        \"editorLineNumber.activeForeground\": \"#858585\",\n      },\n    });\n    monaco.editor.setTheme(\"premium-dark\");\n    props.onMount?.(editor, monaco);\n  };\n\n  return (\n    <div className={cn(\"relative overflow-hidden\", className)}>\n      <Editor\n        loading={\n          loader || (\n            <div className=\"flex items-center justify-center h-full bg-card\">\n              <motion.div\n                {...SPINNER_ANIMATION}\n                className=\"w-8 h-8 border-2 border-emerald-500 border-t-transparent rounded-full\"\n              />\n            </div>\n          )\n        }\n        height={height}\n        width={width}\n        language={language}\n        theme={theme}\n        value={value}\n        onChange={(v) => setValue(v || \"\")}\n        onMount={handleMount}\n        options={{\n          readOnly: disabled,\n          minimap: { enabled: false },\n          fontSize: 14,\n          fontFamily: \"'JetBrains Mono', 'Fira Code', monospace\",\n          lineNumbers: \"on\",\n          folding: true,\n          lineHeight: 22,\n          scrollBeyondLastLine: false,\n          automaticLayout: true,\n          padding: { top: 16, bottom: 16 },\n          cursorBlinking: \"smooth\",\n          smoothScrolling: true,\n          renderLineHighlight: \"line\",\n          bracketPairColorization: { enabled: true },\n          scrollbar: { alwaysConsumeMouseWheel: false },\n          ...props.options,\n        }}\n        {...props}\n      />\n    </div>\n  );\n}\n\nexport type CodeEditorFooterProps = {\n  children?: React.ReactNode;\n  className?: string;\n  showStatus?: boolean;\n  showLanguage?: boolean;\n  showLineNumber?: boolean;\n  showCharCount?: boolean;\n  statusText?: string;\n};\n\nexport function CodeEditorFooter({\n  children,\n  className,\n  showStatus = true,\n  showLanguage = true,\n  showLineNumber = true,\n  showCharCount = true,\n  statusText = \"Ready\",\n}: CodeEditorFooterProps) {\n  const { language, value, cursorLine, cursorColumn, languages } =\n    useCodeEditor();\n  const charCount = value.replace(/\\s/g, \"\").length;\n  const lang = languages.find((l) => l.value === language);\n\n  return (\n    <div\n      className={cn(\n        \"flex flex-wrap items-center justify-between gap-2 px-3 py-2 bg-secondary/50 border-t border-border text-xs font-medium\",\n        className\n      )}\n    >\n      <div className=\"flex flex-wrap items-center gap-2 sm:gap-3\">\n        {showStatus && (\n          <>\n            <span className=\"flex items-center gap-1.5\">\n              <motion.span\n                className=\"w-1.5 h-1.5 rounded-full bg-green-500\"\n                {...PULSE_ANIMATION}\n              />\n              <span className=\"text-muted-foreground\">{statusText}</span>\n            </span>\n            {showLanguage && (\n              <span className=\"text-muted-foreground/50\">•</span>\n            )}\n          </>\n        )}\n        {showLanguage && (\n          <span className=\"flex items-center gap-1.5\">\n            {lang?.icon && (\n              <img src={lang.icon} alt=\"\" className=\"w-3 h-3 opacity-70\" />\n            )}\n            <span className=\"text-muted-foreground\">\n              {lang?.label || language}\n            </span>\n          </span>\n        )}\n      </div>\n      <div className=\"flex flex-wrap items-center gap-2 sm:gap-3\">\n        {children}\n        {showLineNumber && (\n          <>\n            <span className=\"text-muted-foreground\">\n              Ln {cursorLine}, Col {cursorColumn}\n            </span>\n            {showCharCount && (\n              <span className=\"text-muted-foreground/50\">•</span>\n            )}\n          </>\n        )}\n        {showCharCount && (\n          <span className=\"text-muted-foreground\">{charCount} chars</span>\n        )}\n      </div>\n    </div>\n  );\n}\n\nexport type CodeEditorProps = {\n  value?: string;\n  onValueChange?: (v: string) => void;\n  language?: string;\n  onLanguageChange?: (l: string) => void;\n  languages?: Language[];\n  theme?: string;\n  disabled?: boolean;\n  children: React.ReactNode;\n  className?: string;\n};\n\nexport function CodeEditor({\n  value,\n  onValueChange,\n  language = \"python\",\n  onLanguageChange,\n  languages = DEFAULT_LANGUAGES,\n  theme = \"vs-dark\",\n  disabled = false,\n  children,\n  className,\n}: CodeEditorProps) {\n  const [internalValue, setInternalValue] = useState(value ?? \"\");\n  const [internalLanguage, setInternalLanguage] = useState(language);\n  const [cursorLine, setCursorLine] = useState(1);\n  const [cursorColumn, setCursorColumn] = useState(1);\n  const editorRef = useRef<editor.IStandaloneCodeEditor | null>(null);\n\n  const handleValue = (v: string) => {\n    setInternalValue(v);\n    onValueChange?.(v);\n  };\n  const handleLang = (l: string) => {\n    setInternalLanguage(l);\n    onLanguageChange?.(l);\n  };\n  const setCursorPosition = (line: number, col: number) => {\n    setCursorLine(line);\n    setCursorColumn(col);\n  };\n\n  return (\n    <CodeEditorContext.Provider\n      value={{\n        disabled,\n        value: internalValue,\n        setValue: handleValue,\n        language: internalLanguage,\n        setLanguage: handleLang,\n        languages,\n        theme,\n        cursorLine,\n        cursorColumn,\n        setCursorPosition,\n        editorRef,\n      }}\n    >\n      <div\n        className={cn(\n          \"rounded-md overflow-hidden border border-border bg-card\",\n          className\n        )}\n      >\n        {children}\n      </div>\n    </CodeEditorContext.Provider>\n  );\n}\n",
      "type": "registry:component"
    }
  ]
}