'use client'; import { useState, useEffect, useRef } from 'react'; import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; import { vscDarkPlus, vs } from 'react-syntax-highlighter/dist/esm/styles/prism'; import { useTheme } from 'next-themes'; import { Button } from '@/components/ui/button'; import { AlertCircle, CheckCircle2, Wand2 } from 'lucide-react'; import { cn } from '@/lib/utils'; interface McpJsonEditorProps { value: string; onChange: (value: string) => void; placeholder?: string; className?: string; } export function McpJsonEditor({ value, onChange, placeholder, className }: McpJsonEditorProps) { const { theme, resolvedTheme } = useTheme(); const [isValid, setIsValid] = useState(true); const [errorMessage, setErrorMessage] = useState(null); const [isFormatted, setIsFormatted] = useState(false); const textareaRef = useRef(null); const highlightContainerRef = useRef(null); // Determine theme const isDark = resolvedTheme === 'dark' || theme === 'dark'; const codeStyle = isDark ? vscDarkPlus : vs; // Validate JSON and update state const validateJson = (jsonString: string) => { if (!jsonString.trim()) { setIsValid(true); setErrorMessage(null); return; } try { JSON.parse(jsonString); setIsValid(true); setErrorMessage(null); } catch (e) { setIsValid(false); const error = e instanceof Error ? e.message : 'JSON inválido'; setErrorMessage(error); } }; // Format JSON const formatJson = () => { if (!value.trim()) return; try { const parsed = JSON.parse(value); const formatted = JSON.stringify(parsed, null, 2); onChange(formatted); setIsFormatted(true); setTimeout(() => setIsFormatted(false), 2000); } catch (e) { // If invalid, show error validateJson(value); } }; // Handle input changes const handleChange = (e: React.ChangeEvent) => { const newValue = e.target.value; onChange(newValue); validateJson(newValue); setIsFormatted(false); }; // Sync scroll between textarea and highlight const handleScroll = () => { if (textareaRef.current && highlightContainerRef.current) { const scrollTop = textareaRef.current.scrollTop; const scrollLeft = textareaRef.current.scrollLeft; const pre = highlightContainerRef.current.querySelector('pre'); if (pre) { pre.scrollTop = scrollTop; pre.scrollLeft = scrollLeft; } } }; // Validate on mount and when value changes externally useEffect(() => { validateJson(value); }, [value]); // Count lines for display const lineCount = value.split('\n').length; return (
{/* Toolbar */}
{isFormatted && (
Formatado
)}
{lineCount > 0 && {lineCount} linha{lineCount !== 1 ? 's' : ''}} {!isValid && errorMessage && (
{errorMessage}
)} {isValid && value.trim() && (
Válido
)}
{/* Editor Container */}
{/* Syntax Highlighted Background */}
{value || placeholder || '{}'}
{/* Editable Textarea */}