Skip to content

Commit

Permalink
#1463: Add monaco editor to playground
Browse files Browse the repository at this point in the history
  • Loading branch information
k2snowman69 committed May 27, 2023
1 parent b9ceb6f commit 6ad170d
Show file tree
Hide file tree
Showing 10 changed files with 257 additions and 32 deletions.
53 changes: 53 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 3 additions & 4 deletions src-playground/mocks/typescript.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/* eslint-disable */
// @ts-nocheck
const packageJson = require("../../node_modules/typescript/package.json");
// const packageJson = require("../../node_modules/typescript/package.json");
// const json = JSON.parse(packageJson);
// const { version } = json;

if (self.process == null) {
// @ts-ignore
Expand All @@ -10,9 +12,6 @@ if (self.process == null) {
};
}

const json = JSON.parse(packageJson);
const { version } = json;

// Available versions
importScripts(`https://unpkg.com/typescript/lib/typescript.js`);

Expand Down
1 change: 1 addition & 0 deletions src-playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"css-loader": "6.7.4",
"history": "5.3.0",
"html-webpack-plugin": "5.5.1",
"monaco-editor-webpack-plugin": "7.0.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"rimraf": "5.0.1",
Expand Down
125 changes: 125 additions & 0 deletions src-playground/src/components/diff-editor/code-editor/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import * as monaco from "monaco-editor";
import React from "react";
import { SortierWorkerInputData } from "../../../hooks/use-sortier";
import "./styles.css";

export type CodeEditorProps = {
className?: string;
fileType: SortierWorkerInputData["type"];
value: string;
onChange?: (newValue: string) => void;
};

function fileTypeToJsx(fileType: SortierWorkerInputData["type"]): boolean {
switch (fileType) {
case "jsx":
case "tsx":
return true;
default:
return false;
}
}

function fileTypeToLanguage(fileType: SortierWorkerInputData["type"]): string {
switch (fileType) {
case "js":
case "jsx":
return "javascript";
case "ts":
case "tsx":
return "typescript";
default:
return fileType;
}
}

export function CodeEditor(props: CodeEditorProps) {
const { className, fileType, onChange, value } = props;

const ref = React.useRef<HTMLDivElement>(null);

// Calculated values
const readOnly = onChange == null;
const isJsx = fileTypeToJsx(fileType);
const language = fileTypeToLanguage(fileType);
const monacoInstance = React.useMemo(() => {
const { current } = ref;
if (current == null) {
return null;
}
const instance = monaco.editor.create(current, {
automaticLayout: true,
language: language,
readOnly: readOnly,
value: value,
});

return instance;
}, [ref.current]);

// Effects from if props change
React.useEffect(() => {
if (monacoInstance == null) {
return;
}
const newModel = monaco.editor.createModel(value, language);
monacoInstance.setModel(newModel);

if (isJsx) {
monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
jsx: monaco.languages.typescript.JsxEmit.React,
});
monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
jsx: monaco.languages.typescript.JsxEmit.React,
});
} else {
monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
jsx: monaco.languages.typescript.JsxEmit.None,
});
monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
jsx: monaco.languages.typescript.JsxEmit.None,
});
}
}, [monacoInstance, language, isJsx]);

React.useEffect(() => {
if (monacoInstance == null) {
return;
}

const model = monacoInstance.getModel();
if (model == null) {
return;
}

if (model.getValue() !== value) {
model.setValue(value);
}
}),
[monacoInstance, value];

React.useEffect(() => {
if (monacoInstance == null) {
return;
}
if (onChange == null) {
return;
}

const listener = monacoInstance.onDidChangeModelContent(() => {
onChange(monacoInstance.getValue());
});

return () => {
listener.dispose();
};
}),
[monacoInstance, onChange];

// Render
return (
<div className="site--diff-editor--code-editor">
<div className={className} ref={ref}></div>
</div>
);
}
11 changes: 11 additions & 0 deletions src-playground/src/components/diff-editor/code-editor/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.site--diff-editor--code-editor {
position: relative;
}

.site--diff-editor--code-editor > * {
bottom: 0px;
left: 0px;
position: absolute;
right: 0px;
top: 0px;
}
18 changes: 7 additions & 11 deletions src-playground/src/components/diff-editor/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { ChangeEvent } from "react";
import React from "react";
import { SortierWorkerInputData } from "../../hooks/use-sortier";
import { CodeEditor } from "./code-editor";
import "./styles.css";

export type DiffEditorProps = {
Expand All @@ -10,24 +11,19 @@ export type DiffEditorProps = {
};

export function DiffEditor(props: DiffEditorProps) {
const { inputText, onInputTextChange, outputText } = props;
const { fileType, inputText, onInputTextChange, outputText } = props;

const onTextChange = React.useCallback(
(e: ChangeEvent<HTMLTextAreaElement>) => {
onInputTextChange(e.currentTarget.value);
(e: string) => {
onInputTextChange(e);
},
[onInputTextChange]
);

return (
<div className="site--diff-editor">
<textarea
className="input"
name="text"
onChange={onTextChange}
value={inputText}
/>
<textarea className="output" name="text" readOnly value={outputText} />
<CodeEditor className="input" fileType={fileType} onChange={onTextChange} value={inputText} />
<CodeEditor className="output" fileType={fileType} value={outputText} />
</div>
);
}
8 changes: 2 additions & 6 deletions src-playground/src/hooks/use-sortier/format-text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ function getWorker(fileType: SortierWorkerInputData["type"]) {
case "jsx":
case "ts":
case "tsx":
return new Worker(
new URL("./format-workers/javascript", import.meta.url)
);
return new Worker(new URL("./format-workers/javascript", import.meta.url));
default:
throw new Error(`File type ${fileType} not supported`);
}
Expand All @@ -25,9 +23,7 @@ export function useSortier(initialInput: SortierWorkerInputData) {
const [outputText, setOutputText] = useState(loadingFormatterMessage);
const [worker, setWorker] = useState<null | Worker>();
const [input, setInput] = useState<SortierWorkerInputData>(initialInput);
const [type, setType] = useState<SortierWorkerInputData["type"]>(
initialInput.type
);
const [type, setType] = useState<SortierWorkerInputData["type"]>(initialInput.type);

useEffect(() => {
worker?.terminate();
Expand Down
10 changes: 10 additions & 0 deletions src-playground/src/utilities/default-text/html.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<h1>Hello world!</h1>
<p>Welcome to sortier!</p>
</body>
</html>
25 changes: 19 additions & 6 deletions src-playground/src/utilities/default-text/tsx.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
type Options = {
import React from "react";

export type OptionsProps = {
sleep?: number;
write?: boolean;
logLevel?: "quiet" | "normal" | "diagnostic";
};

const options: Options = {
sleep: 30,
write: true,
logLevel: "diagnostic",
};
export function OptionsViewer(props: OptionsProps) {
const { logLevel, sleep, write } = props;

return (
<div>
<dl>
<dt>Log Level</dt>
<dl>{logLevel}</dl>
<dt>Sleep</dt>
<dl>{sleep}</dl>
<dt>Write</dt>
<dl>{write}</dl>
</dl>
</div>
);
}
Loading

0 comments on commit 6ad170d

Please sign in to comment.