Skip to content

Instantly share code, notes, and snippets.

@Jaid
Created September 22, 2025 04:50
Show Gist options
  • Select an option

  • Save Jaid/84cfa97744dbd8a816d6102e816a3973 to your computer and use it in GitHub Desktop.

Select an option

Save Jaid/84cfa97744dbd8a816d6102e816a3973 to your computer and use it in GitHub Desktop.

Revisions

  1. Jaid created this gist Sep 22, 2025.
    174 changes: 174 additions & 0 deletions YamlEditor.tsx
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,174 @@
    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;