Created
September 22, 2025 04:50
-
-
Save Jaid/84cfa97744dbd8a816d6102e816a3973 to your computer and use it in GitHub Desktop.
YamlEditor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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