Skip to content

Instantly share code, notes, and snippets.

@Jaid
Created September 22, 2025 04:50
Show Gist options
  • Save Jaid/84cfa97744dbd8a816d6102e816a3973 to your computer and use it in GitHub Desktop.
Save Jaid/84cfa97744dbd8a816d6102e816a3973 to your computer and use it in GitHub Desktop.
YamlEditor
import type { OnMount } from "@monaco-editor/react";
import type { FileRejection } from "react-dropzone";
import Editor from "@monaco-editor/react";
import React, { useCallback, useRef, useState } from "react";
import { useDropzone } from "react-dropzone";
import { useHotkeys } from "react-hotkeys-hook";
import * as YAML from "yaml";
interface YamlEditorProps {
black: boolean;
initialValue: string;
onDataChange: (data: any) => void;
useGlobalHotkeys?: boolean;
}
const YamlEditor: React.FC<YamlEditorProps> = (props) => {
const editorRef = useRef<any>(null);
const [code, setCode] = useState(props.initialValue);
const handleEditorDidMount: OnMount = (editor, monaco) => {
editorRef.current = editor;
if (props.black) {
monaco.editor.defineTheme(`custom`, {
base: `vs-dark`,
inherit: true,
rules: [],
colors: {
"editor.background": `#000000`,
},
});
monaco.editor.setTheme(`custom`);
}
editor.addAction({
id: `copy-as-json`,
label: `Copy as JSON`,
contextMenuGroupId: `navigation`,
contextMenuOrder: 1.5,
run: (ed) => {
const val = ed.getValue();
try {
const parsed = YAML.parse(val);
const jsonStr = JSON.stringify(parsed, null, 2);
navigator.clipboard
.writeText(jsonStr)
.then(() => {
console.log(`Copied as JSON`);
})
.catch((error) => {
console.error(`Failed to copy: `, error);
});
} catch (error) {
console.error(`Invalid YAML: `, error);
alert(`Invalid YAML, cannot copy as JSON`);
}
},
});
};
const updateContent = (newCode: string) => {
setCode(newCode);
try {
const parsedData = YAML.parse(newCode);
if (Array.isArray(parsedData)) {
props.onDataChange(parsedData);
}
} catch (error) {
console.error(`Invalid YAML:`, error);
}
};
const onDrop = useCallback(
async (
acceptedFiles: Array<File>,
fileRejections: Array<FileRejection>
) => {
if (fileRejections.length > 0) {
console.error(`File rejected:`, fileRejections);
return;
}
const file = acceptedFiles[0];
try {
const text = await file.text();
let yamlText = text;
if (file.name.endsWith(`.json`)) {
const jsonData = JSON.parse(text);
yamlText = YAML.stringify(jsonData);
} else if (file.name.endsWith(`.jsonl`)) {
const lines = text.trim().split(`\n`);
const jsonData = lines.map((line) => JSON.parse(line));
yamlText = YAML.stringify(jsonData);
}
updateContent(yamlText);
} catch (error) {
console.error(`Error processing dropped file:`, error);
}
},
[]
);
const { getRootProps, getInputProps, isDragActive } = useDropzone({
onDrop,
noClick: true,
noKeyboard: true,
multiple: false,
accept: {
"text/yaml": [`.yaml`, `.yml`],
"application/json": [`.json`],
"application/jsonl": [`.jsonl`],
},
});
if (props.useGlobalHotkeys) {
useHotkeys(
`e`,
(e) => {
e.preventDefault();
editorRef.current?.focus();
},
{ enableOnFormTags: true }
);
}
return (
<div
{...getRootProps()}
style={{
position: `relative`,
height: `100%`,
width: `100%`,
}}
>
<input {...getInputProps()} />
{isDragActive && (
<div
style={{
position: `absolute`,
top: 0,
left: 0,
right: 0,
bottom: 0,
background: `rgba(20, 20, 20, 0.85)`,
display: `flex`,
alignItems: `center`,
justifyContent: `center`,
zIndex: 10,
border: `2px dashed #555`,
borderRadius: `8px`,
color: `#ccc`,
fontSize: `1.2rem`,
pointerEvents: `none`,
}}
>
Drop YAML, JSON, or JSONL file here
</div>
)}
<Editor
defaultLanguage="yaml"
value={code}
onMount={handleEditorDidMount}
onChange={(value) => updateContent(value ?? ``)}
theme="vs-dark"
options={{
minimap: { enabled: false },
stickyScroll: { enabled: false },
lineNumbers: `off`,
fontFamily: `JetBrainsMono NF, monospace`,
tabSize: 2,
dragAndDrop: false,
accessibilitySupport: `off`,
guides: { indentation: false },
lineHeight: 1.3,
renderWhitespace: `trailing`,
wordWrap: `on`,
}}
/>
</div>
);
};
export default YamlEditor;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment