remcohaszing/monaco-yaml

configureyaml is not working with @monaco-editor/react

Closed this issue · 12 comments

Is there a different approach for @monaco-editor/react
can you please share an example of how can we do configuration with @monaco-editor/react
this is my code
useEffect(() => {
window.MonacoEnvironment = {
getWorker(moduleId, label) {
switch (label) {
case "editorWorkerService":
return new Worker(
new URL("monaco-editor/esm/vs/editor/editor.worker", import.meta.url)
);
case "yaml":
return new Worker(new URL("monaco-yaml/yaml.worker", import.meta.url));
default:
throw new Error(Unknown label ${label});
}
},
};

// Configure Monaco YAML
const defaultSchema = {
  uri: 'https://github.com/remcohaszing/monaco-yaml/blob/HEAD/examples/demo/src/schema.json',
  schema,
  fileMatch: ['monaco-yaml.yaml']
}
if (window.monaco) {
  const monacoYaml = configureMonacoYaml(window.monaco, {
    enableSchemaRequest: true,
    schemas: [defaultSchema],
  });
}

}, [window.monaco]);

Please format your code and provide a full runnable example, such as a repository that reproduces the problem.

My personal recommendation is to not use @monaco-editor/react, but use monaco-editor directly.

Thank you sir for replying I am attaching my editorcomponent file, please look into that.
Great work sir

import Editor from '@monaco-editor/react';
import React, { useEffect } from 'react';
import './index.css';
import { configureMonacoYaml } from "monaco-yaml";
import schema from "./schema.json";
const MonacoEditorComponent = () => {

  useEffect(() => {
    // Configure Monaco Editor
    window.MonacoEnvironment = {
      getWorker(moduleId, label) {
        switch (label) {
          case "yaml":
            return new Worker(new URL("monaco-yaml/yaml.worker", import.meta.url));
          default:
            throw new Error(`Unknown label ${label}`);
        }
      },
    };

  }, []);
  const value = `
  # Property descriptions are displayed when hovering over properties using your cursor
  property: This property has a JSON schema description


  # Titles work too!
  titledProperty: Titles work too!


  # Even markdown descriptions work
  markdown: hover me to get a markdown based description 😮


  # Enums can be autocompleted by placing the cursor after the colon and pressing Ctrl+Space
  enum:


  # Unused anchors will be reported
  unused anchor: &unused anchor


  # Of course numbers are supported!
  number: 12


  # As well as booleans!
  boolean: true


  # And strings
  string: I am a string


  # This property is using the JSON schema recursively
  reference:
    boolean: Not a boolean


  # Also works in arrays
  array:
    - string: 12
      enum: Mewtwo
      reference:
        reference:
          boolean: true


  # JSON referenses can be clicked for navigation
  pointer:
    $ref: '#/array'


  # This anchor can be referenced
  anchorRef: &anchor can be clicked as well


  # Press control while hovering over the anchor
  anchorPointer: *anchor


  formatting:       Formatting is supported too! Under the hood this is powered by Prettier. Just press Ctrl+Shift+I or right click and press Format to format this document.






  `.replace(/:$/m, ": ");

  return (
    <div id="editor" style={{ height: "100vh", textAlign: "left" }} >
      <Editor
        defaultLanguage='yaml'
        value={value}
        onMount={(editor, monaco) => {
          const defaultSchema = {
            uri: "file://./src/schema.json",
            schema,
            fileMatch: ["monaco-yaml.yaml"],
          };

          const monacoYaml = configureMonacoYaml(monaco, {
            enableSchemaRequest: true,
            schemas: [defaultSchema],
          });
        }}
      />
    </div>
  )
};

export default MonacoEditorComponent;

Sir Can you please help me with this given code

I use it with react-monaco-editor but it should be roughly the same...

Add this to your file:

import * as monacoEditor from 'monaco-editor/esm/vs/editor/editor.api';

const monacoYaml = configureMonacoYaml(monacoEditor);

And on mount use monacoYaml.update instead of configureMonacoYaml:

monacoYaml.update({
  enableSchemaRequest: true,
  schemas: [defaultSchema],
});

@abemedia Sir I tried this way also, but it is not working, I am attaching my entire code if you have time please check it once.
test.zip

Surprisingly running into the same issue where I get no errors but schema and auto completion is not working

Surprisingly running into the same issue where I get no errors but schema and auto completion is not working

Are you able to find any solution for this?

@Rajgupta7080 Well, I've realized that what appears to be happening is the yamlWorker is never started on my end. Not sure why.

@Rajgupta7080 I have it working. Switch from onMount to beforeMount

@TerminalFi If you don't mind can you please share example of that working code, I tried before mount also it is not working for me.

@TerminalFi If you don't mind can you please share example of that working code, I tried before mount also it is not working for me.

This is what my page Editor looks like

"use client";

import PageSpinner from "@/components/PageSpinner";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Database } from "@/lib/db/database";
import Editor, { BeforeMount, OnMount, type Monaco } from "@monaco-editor/react";
import { AlertTriangle } from "lucide-react";
import { editor } from "monaco-editor";
import { configureMonacoYaml } from 'monaco-yaml';
import { useTheme } from "next-themes";
import { useEffect, useRef, useState } from "react";
import toast from "react-hot-toast";
import SaveButton from "./SaveButton";
import { updateMetadata } from "./actions";

type Repository = Database["public"]["Tables"]["repositories"]["Row"];

interface MetadataEditorProps {
  repository: Repository | null;
}

window.MonacoEnvironment = {
  getWorker(_, label) {
    switch (label) {
      case 'yaml':
        return new Worker(new URL('monaco-yaml/yaml.worker', import.meta.url))
      default:
        return new Worker(new URL('monaco-editor/esm/vs/editor/editor.worker', import.meta.url))
    }
  }
}

export default function MetadataEditor({ repository }: MetadataEditorProps) {
  const monacoRef = useRef<editor.IStandaloneCodeEditor | null>(null);
  const { theme, setTheme } = useTheme();
  const [isValid, setIsValid] = useState(true);
  const [errors, setErrors] = useState<string[]>([]);
  const [metadata, setMetadata] = useState(repository!.metadata || "");

  // If the parent repository metadata changes, update the editor value
  // this should only really happen if the user tries to save an empty string as the metadata
  useEffect(() => {
    setMetadata(repository!.metadata || "");
  }, [repository]);

  var monacoOptions = {
    readOnly: false,
    minimap: { enabled: false },
    formatOnType: true,
    formatOnPaste: true,
    quickSuggestions: {
      other: true,
      comments: false,
      strings: true,
    },
  };

  const handleEditorWillMount: BeforeMount = (monaco: Monaco) => {
    configureMonacoYaml(monaco, {
      enableSchemaRequest: true,
      hover: true,
      completion: true,
      validate: true,
      format: true,
      schemas: [
        {
          uri: '/schema.json',
          fileMatch: ['*'],
        },
      ],
    })
  };

  const handleEditorDidMount: OnMount = (editor, monaco: Monaco) => {
    monacoRef.current = editor;
  };

  function validateEvent(validationErrors: any) {
    setIsValid(validationErrors.length === 0);
    if (validationErrors.length > 0) {
      setErrors(validationErrors.map((error: any) => error.message));
    }
  }

  async function saveMetadata(formData: FormData) {
    if (isValid) {
      let yamlMetadata = monacoRef.current!.getValue();

      let result = await updateMetadata(repository!.uuid, yamlMetadata);
      if (result?.error) {
        toast.error(result.error);
        return;
      }
      toast.success("Metadata Changes Saved");
      monacoRef!.current!.getAction("editor.action.formatDocument")!.run();
    } else {
      toast.error("Metadata is invalid. Please fix the errors and try again.");
    }
  }

  let editorTheme = theme === "light" ? "light" : "vs-dark";

  return (
    <div>
      <Editor
        className="rounded-lg border"
        height="40vh"
        theme={editorTheme}
        onValidate={validateEvent}
        beforeMount={handleEditorWillMount}
        onMount={handleEditorDidMount}
        value={metadata.toString()}
        loading={<PageSpinner />}
        options={monacoOptions}
        defaultLanguage="yaml"
        language="yaml"
      />
      {isValid ? (
        null
      ) : (
        <Alert className="mt-5 bg-yellow-100 dark:bg-yellow-800">
          <AlertTriangle className="h-4 w-4" />
          <AlertTitle>Invalid YAML</AlertTitle>
          <AlertDescription>

            {errors.map((error, index) => {
              return <p key={index}>{error}</p>
            }
            )}
          </AlertDescription>
        </Alert>
      )}
      <form action={saveMetadata}>
        <SaveButton />
      </form>
    </div>
  );
}

@TerminalFi Sir, Thank you so much for sharing this code, Now my code started working.