"use client"; import Editor from "@monaco-editor/react"; import debounce from "lodash/debounce"; import React, { useEffect, useState, useRef, useCallback } from "react"; import { wrapFieldsWithMeta } from "tinacms"; const MINIMUM_HEIGHT = 75; if (typeof window !== "undefined") { import("@monaco-editor/react") .then(({ loader }) => { loader.config({ paths: { vs: "https://cdn.jsdelivr.net/npm/monaco-editor@0.31.1/min/vs", }, }); }) .catch((e) => { // Failed to load Monaco editor }); } const MonacoCodeEditor = wrapFieldsWithMeta(({ input }) => { const [value, setValue] = useState(input.value || ""); const [editorHeight, setEditorHeight] = useState(MINIMUM_HEIGHT); const [isLoaded, setIsLoaded] = useState(false); const editorRef = useRef(null); const lastSavedValue = useRef(input.value || ""); const updateTinaValue = useCallback( debounce((newValue: string) => { lastSavedValue.current = newValue; input.onChange(newValue); }, 100), [] ); useEffect(() => { if (input.value !== lastSavedValue.current && input.value !== value) { setValue(input.value || ""); lastSavedValue.current = input.value || ""; } }, [input.value, value]); const handleEditorDidMount = useCallback( (editor: any, monaco: any) => { editorRef.current = editor; if (monaco?.languages?.typescript) { monaco.languages.typescript.javascriptDefaults.setEagerModelSync(true); monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({ noSemanticValidation: true, noSyntaxValidation: true, }); } editor.onDidContentSizeChange(() => { const contentHeight = Math.max( editor.getContentHeight(), MINIMUM_HEIGHT ); setEditorHeight(contentHeight); editor.layout(); }); editor.onDidChangeModelContent(() => { const currentValue = editor.getValue(); if (currentValue !== lastSavedValue.current) { setValue(currentValue); updateTinaValue(currentValue); } }); // Mark as loaded and focus after a brief delay for smooth transition setTimeout(() => { setIsLoaded(true); setTimeout(() => { try { editorRef.current?.focus(); } catch (e) { // Error focusing editor silently ignored } }, 200); }, 100); }, [updateTinaValue] ); const handleBeforeMount = useCallback(() => {}, []); const editorOptions = { scrollBeyondLastLine: false, tabSize: 2, disableLayerHinting: true, accessibilitySupport: "off" as const, codeLens: false, wordWrap: "on" as const, minimap: { enabled: false, }, fontSize: 14, lineHeight: 2, formatOnPaste: true, lineNumbers: "on" as const, formatOnType: true, fixedOverflowWidgets: true, folding: false, renderLineHighlight: "none" as const, scrollbar: { verticalScrollbarSize: 1, horizontalScrollbarSize: 1, alwaysConsumeMouseWheel: false, }, automaticLayout: true, }; return (
{!isLoaded && (
Loading editor...
)}
); }); export default MonacoCodeEditor;