Skip to main content
Glama
JsonCodeEditor.tsx5.92 kB
import { useMonacoTheme } from '@/src/hooks/useMonacoTheme'; import { cn } from '@/src/lib/general-utils'; import Editor from '@monaco-editor/react'; import React, { useMemo, useState } from 'react'; import { CopyButton } from '../tools/shared/CopyButton'; const HIGHLIGHTING_THRESHOLD = 100 * 1024; // 100KB type JsonCodeEditorProps = { value: string; onChange?: (value: string) => void; readOnly?: boolean; minHeight?: string; maxHeight?: string; placeholder?: string; overlay?: React.ReactNode; bottomRightOverlay?: React.ReactNode; resizable?: boolean; showValidation?: boolean; } export const JsonCodeEditor = ( { value, onChange, readOnly = false, minHeight = '150px', maxHeight = '300px', placeholder = '{}', overlay, bottomRightOverlay, resizable = false, showValidation = false }: JsonCodeEditorProps) => { const { theme, onMount } = useMonacoTheme(); const [currentHeight, setCurrentHeight] = useState(maxHeight); const [jsonError, setJsonError] = useState<string | null>(null); const displayValue = useMemo(() => { const base = value || placeholder; if (readOnly && (base?.length || 0) > HIGHLIGHTING_THRESHOLD) return `${base.slice(0, HIGHLIGHTING_THRESHOLD)}\n...truncated...`; return base; }, [value, placeholder, readOnly]); return ( <div className={cn("relative rounded-lg border shadow-sm bg-muted/30")}> {overlay && (<div className="absolute top-1 right-1 z-10 mr-5 flex items-center gap-1">{overlay}</div>)} {bottomRightOverlay && (<div className="absolute bottom-1 right-1 z-10 mr-5 flex items-center gap-1">{bottomRightOverlay}</div>)} {!overlay && (<div className="absolute top-1 right-1 z-10 mr-5"><CopyButton text={value || placeholder} /></div>)} {resizable && ( <div className="absolute bottom-1 right-1 w-3 h-3 cursor-se-resize z-10" style={{ background: 'linear-gradient(135deg, transparent 50%, rgba(100,100,100,0.3) 50%)' }} onMouseDown={(e) => { e.preventDefault(); const startY = e.clientY; const startHeight = parseInt(currentHeight); const handleMouseMove = (e: MouseEvent) => { const deltaY = e.clientY - startY; const newHeight = Math.max(60, Math.min(600, startHeight + deltaY)); setCurrentHeight(`${newHeight}px`); }; const handleMouseUp = () => { document.removeEventListener('mousemove', handleMouseMove); document.removeEventListener('mouseup', handleMouseUp); }; document.addEventListener('mousemove', handleMouseMove); document.addEventListener('mouseup', handleMouseUp); }} /> )} <div className={cn("overflow-hidden px-3", readOnly ? "cursor-not-allowed" : "cursor-text")} style={{ height: resizable ? currentHeight : maxHeight }}> <Editor height={resizable ? currentHeight : maxHeight} defaultLanguage="json" value={displayValue} onChange={(newValue) => { const val = newValue || ''; onChange?.(val); if (showValidation) { try { if (val && val.trim()) { JSON.parse(val); setJsonError(null); } else { setJsonError(null); } } catch (e) { setJsonError((e as Error).message); } } }} onMount={onMount} options={{ readOnly, minimap: { enabled: false }, fontSize: 12, lineNumbers: 'off', glyphMargin: false, folding: false, lineDecorationsWidth: 0, lineNumbersMinChars: 0, scrollBeyondLastLine: false, wordWrap: 'on', contextmenu: false, renderLineHighlight: 'none', scrollbar: { vertical: 'auto', horizontal: 'auto', verticalScrollbarSize: 8, horizontalScrollbarSize: 8, alwaysConsumeMouseWheel: false }, overviewRulerLanes: 0, hideCursorInOverviewRuler: true, overviewRulerBorder: false, padding: { top: 12, bottom: 12 }, quickSuggestions: false, parameterHints: { enabled: false }, codeLens: false, links: false, colorDecorators: false, occurrencesHighlight: 'off', renderValidationDecorations: 'off', stickyScroll: { enabled: false } }} theme={theme} className="bg-transparent" /> </div> {showValidation && jsonError && ( <div className="absolute bottom-0 left-0 right-0 p-2 bg-destructive/10 text-destructive text-xs max-h-32 overflow-y-auto overflow-x-hidden"> Error: {jsonError} </div> )} </div> ); };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/superglue-ai/superglue'

If you have feedback or need assistance with the MCP directory API, please join our Discord server