index.tsx 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import React from "react";
  2. import Editor, { loader, Monaco } from "@monaco-editor/react";
  3. import debounce from "lodash.debounce";
  4. import { Loading } from "src/components/Loading";
  5. import useJson from "src/store/useJson";
  6. import useStored from "src/store/useStored";
  7. import styled from "styled-components";
  8. loader.config({
  9. paths: {
  10. vs: "https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.34.0/min/vs",
  11. },
  12. });
  13. const editorOptions = {
  14. formatOnPaste: true,
  15. minimap: {
  16. enabled: false,
  17. },
  18. };
  19. const StyledWrapper = styled.div`
  20. display: grid;
  21. height: calc(100vh - 36px);
  22. grid-template-columns: 100%;
  23. grid-template-rows: minmax(0, 1fr);
  24. `;
  25. export const MonacoEditor = () => {
  26. const json = useJson(state => state.json);
  27. const setJson = useJson(state => state.setJson);
  28. const setError = useJson(state => state.setError);
  29. const [loaded, setLoaded] = React.useState(false);
  30. const [value, setValue] = React.useState<string | undefined>(json);
  31. const hasError = useJson(state => state.hasError);
  32. const lightmode = useStored(state => (state.lightmode ? "light" : "vs-dark"));
  33. const handleEditorWillMount = React.useCallback(
  34. (monaco: Monaco) => {
  35. monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
  36. allowComments: true,
  37. comments: "ignore",
  38. });
  39. monaco.editor.onDidChangeMarkers(([uri]) => {
  40. const markers = monaco.editor.getModelMarkers({ resource: uri });
  41. setError(!!markers.length);
  42. });
  43. },
  44. [setError]
  45. );
  46. const debouncedSetJson = React.useMemo(
  47. () =>
  48. debounce(value => {
  49. if (hasError) return;
  50. setJson(value || "[]");
  51. }, 1200),
  52. [hasError, setJson]
  53. );
  54. React.useEffect(() => {
  55. if ((value || !hasError) && loaded) debouncedSetJson(value);
  56. setLoaded(true);
  57. return () => debouncedSetJson.cancel();
  58. // eslint-disable-next-line react-hooks/exhaustive-deps
  59. }, [debouncedSetJson, hasError, value]);
  60. return (
  61. <StyledWrapper>
  62. <Editor
  63. value={json}
  64. theme={lightmode}
  65. options={editorOptions}
  66. onChange={setValue}
  67. loading={<Loading message="Loading Editor..." />}
  68. beforeMount={handleEditorWillMount}
  69. defaultLanguage="json"
  70. height="100%"
  71. />
  72. </StyledWrapper>
  73. );
  74. };