diff --git a/editor-packages/editor-services-esbuild/index.ts b/editor-packages/editor-services-esbuild/index.ts index 724ac3e3..6214ef24 100644 --- a/editor-packages/editor-services-esbuild/index.ts +++ b/editor-packages/editor-services-esbuild/index.ts @@ -1,12 +1,8 @@ -import { Monaco } from "@monaco-editor/react"; import { nanoid } from "nanoid"; import { build, initialize, Loader } from "esbuild-wasm"; import { fetchPlugin } from "./fetch.plugin"; import { unpkgPathPlugin } from "./unpkg-path.plugin"; - -declare const window: { - monaco: Monaco; -}; +import { loadTypes } from "@code-editor/estypes-resolver"; let serviceLoaded: boolean | null = null; @@ -66,55 +62,3 @@ export const normalizeCss = (data: string) => { }; export default bundler; - -let typesWorker; - -const loadTypes = (types) => { - const disposables: any = []; - const monaco = window && window.monaco; - - const dependencies = types.map((e) => ({ name: e, version: "latest" })) || []; - - if (!typesWorker) { - typesWorker = new Worker( - new URL("./workers/fetch-types.worker.js", import.meta.url) - ); - } - - dependencies.forEach((dep) => { - typesWorker.postMessage({ - name: dep.name, - version: dep.version, - }); - }); - - typesWorker.addEventListener("message", (event) => { - // name, - // version, - // typings: result, - const key = `node_modules/${event.data.name}/index.d.ts`; - const source = event.data.typings[key]; - - // const path = `${MONACO_LIB_PREFIX}${event.data.name}`; - const libUri = `file:///node_modules/@types/${event.data.name}/index.d.ts`; - - disposables.push( - monaco.languages.typescript.javascriptDefaults.addExtraLib(source, libUri) - ); - disposables.push( - monaco.languages.typescript.typescriptDefaults.addExtraLib(source, libUri) - ); - - // When resolving definitions and references, the editor will try to use created models. - // Creating a model for the library allows "peek definition/references" commands to work with the library. - }); - - return { - dispose() { - disposables.forEach((d) => d.dispose()); - if (typesWorker) { - typesWorker.terminate(); - } - }, - }; -}; diff --git a/editor-packages/editor-services-estypes-resolver/index.ts b/editor-packages/editor-services-estypes-resolver/index.ts new file mode 100644 index 00000000..85e62cbe --- /dev/null +++ b/editor-packages/editor-services-estypes-resolver/index.ts @@ -0,0 +1,57 @@ +import { Monaco } from "@monaco-editor/react"; + +declare const window: { + monaco: Monaco; +}; + +let typesWorker; + +export function loadTypes(types: string[]) { + const disposables: any = []; + const monaco = window && window.monaco; + + const dependencies = types.map((e) => ({ name: e, version: "latest" })) || []; + + if (!typesWorker) { + typesWorker = new Worker( + new URL("./workers/fetch-types.worker.js", import.meta.url) + ); + } + + dependencies.forEach((dep) => { + typesWorker.postMessage({ + name: dep.name, + version: dep.version, + }); + }); + + typesWorker.addEventListener("message", (event) => { + // name, + // version, + // typings: result, + const key = `node_modules/${event.data.name}/index.d.ts`; + const source = event.data.typings[key]; + + // const path = `${MONACO_LIB_PREFIX}${event.data.name}`; + const libUri = `file:///node_modules/@types/${event.data.name}/index.d.ts`; + + disposables.push( + monaco.languages.typescript.javascriptDefaults.addExtraLib(source, libUri) + ); + disposables.push( + monaco.languages.typescript.typescriptDefaults.addExtraLib(source, libUri) + ); + + // When resolving definitions and references, the editor will try to use created models. + // Creating a model for the library allows "peek definition/references" commands to work with the library. + }); + + return { + dispose() { + disposables.forEach((d) => d.dispose()); + if (typesWorker) { + typesWorker.terminate(); + } + }, + }; +} diff --git a/editor-packages/editor-services-estypes-resolver/package.json b/editor-packages/editor-services-estypes-resolver/package.json new file mode 100644 index 00000000..e7b2a4eb --- /dev/null +++ b/editor-packages/editor-services-estypes-resolver/package.json @@ -0,0 +1,5 @@ +{ + "name": "@code-editor/estypes-resolver", + "version": "0.0.0", + "private": false +} \ No newline at end of file diff --git a/editor-packages/editor-services-esbuild/workers/fetch-types.worker.js b/editor-packages/editor-services-estypes-resolver/workers/fetch-types.worker.js similarity index 100% rename from editor-packages/editor-services-esbuild/workers/fetch-types.worker.js rename to editor-packages/editor-services-estypes-resolver/workers/fetch-types.worker.js diff --git a/editor/components/code-editor/code-editor.tsx b/editor/components/code-editor/code-editor.tsx index 33665d02..bfefce49 100644 --- a/editor/components/code-editor/code-editor.tsx +++ b/editor/components/code-editor/code-editor.tsx @@ -51,8 +51,8 @@ export function CodeEditor({ onChange={(v: string, e) => { onChange?.(filekey, v, e); }} - defaultLanguage={file.language} - defaultValue={file.raw} + language={file.language} + value={file.raw} /> ); diff --git a/editor/components/code-editor/monaco-utils/register-preset-types.ts b/editor/components/code-editor/monaco-utils/register-preset-types.ts new file mode 100644 index 00000000..e9c61041 --- /dev/null +++ b/editor/components/code-editor/monaco-utils/register-preset-types.ts @@ -0,0 +1,21 @@ +import { loadTypes } from "@code-editor/estypes-resolver"; + +const react_preset_dependencies = [ + "react", + "react-dom", + "prop-types", + "react-router", + "react-router-dom", + "styled-components", + "@emotion/styled", + "@emotion/react", + "axios", +]; + +/** + * load the preset dependencies on initial boot (e.g. react) + */ +export function registerPresetTypes() { + // load the react presets + loadTypes(react_preset_dependencies); +} diff --git a/editor/components/code-editor/monaco-utils/register.ts b/editor/components/code-editor/monaco-utils/register.ts index 354982d0..866eb037 100644 --- a/editor/components/code-editor/monaco-utils/register.ts +++ b/editor/components/code-editor/monaco-utils/register.ts @@ -2,12 +2,14 @@ import * as monaco from "monaco-editor"; import { Monaco, OnMount } from "@monaco-editor/react"; import { registerDocumentPrettier } from "@code-editor/prettier-services"; import { registerJsxHighlighter } from "@code-editor/jsx-syntax-highlight-services"; +import { registerPresetTypes } from "./register-preset-types"; type CompilerOptions = monaco.languages.typescript.CompilerOptions; export const initEditor: OnMount = (editor, monaco) => { registerJsxHighlighter(editor, monaco); registerDocumentPrettier(editor, monaco); + registerPresetTypes(); }; export const initMonaco = (monaco: Monaco) => { diff --git a/editor/components/code-editor/monaco.tsx b/editor/components/code-editor/monaco.tsx index b949eb17..8071818c 100644 --- a/editor/components/code-editor/monaco.tsx +++ b/editor/components/code-editor/monaco.tsx @@ -1,20 +1,16 @@ -import React, { useRef, useEffect } from "react"; -import Editor, { - useMonaco, - Monaco, - OnMount, - OnChange, -} from "@monaco-editor/react"; +import React, { useRef } from "react"; +import Editor, { OnMount, OnChange } from "@monaco-editor/react"; import * as monaco from "monaco-editor/esm/vs/editor/editor.api"; import { MonacoEmptyMock } from "./monaco-mock-empty"; import { register } from "./monaco-utils"; import { __dangerous__lastFormattedValue__global } from "@code-editor/prettier-services"; +import { debounce } from "utils/debounce"; type ICodeEditor = monaco.editor.IStandaloneCodeEditor; export interface MonacoEditorProps { - defaultValue?: string; - defaultLanguage?: string; + value?: string; + language?: string; onChange?: OnChange; width?: number | string; height?: number | string; @@ -23,7 +19,6 @@ export interface MonacoEditorProps { export function MonacoEditor(props: MonacoEditorProps) { const instance = useRef<{ editor: ICodeEditor; format: any } | null>(null); - const activeModel = useRef(); const onMount: OnMount = (editor, monaco) => { const format = editor.getAction("editor.action.formatDocument"); @@ -31,8 +26,6 @@ export function MonacoEditor(props: MonacoEditorProps) { instance.current = { editor, format }; - activeModel.current = editor.getModel(); - register.initEditor(editor, monaco); editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, function () { @@ -41,6 +34,7 @@ export function MonacoEditor(props: MonacoEditorProps) { // disabled. todo: find a way to format on new line, but also with adding new line. // editor.addCommand(monaco.KeyCode.Enter, function () { + // // add new line via script, then run format // format.run(); // }); @@ -50,9 +44,9 @@ export function MonacoEditor(props: MonacoEditorProps) { rename.run(); }); - editor.onDidChangeModelContent((e) => { - /* add here */ - }); + editor.onDidChangeModelContent(() => + debounce(() => editor.saveViewState(), 200) + ); }; return ( @@ -61,11 +55,10 @@ export function MonacoEditor(props: MonacoEditorProps) { onMount={onMount} width={props.width} height={props.height} - defaultLanguage={ - pollyfill_language(props.defaultLanguage) ?? "typescript" - } + language={pollyfill_language(props.language) ?? "typescript"} + path={"app." + lang2ext(props.language)} loading={} - defaultValue={props.defaultValue ?? "// no content"} + value={props.value ?? "// no content"} theme="vs-dark" onChange={(...v) => { if (v[0] === __dangerous__lastFormattedValue__global) { @@ -84,6 +77,23 @@ export function MonacoEditor(props: MonacoEditorProps) { ); } +const lang2ext = (lang: string) => { + switch (lang) { + case "typescript": + return "ts"; + case "javascript": + return "js"; + case "tsx": + return "tsx"; + case "jsx": + return "jsx"; + case "dart": + return "dart"; + default: + return lang; + } +}; + const pollyfill_language = (lang: string) => { switch (lang) { case "tsx": diff --git a/editor/pages/figma/inspect-frame.tsx b/editor/pages/figma/inspect-frame.tsx index e1a2f037..7222de65 100644 --- a/editor/pages/figma/inspect-frame.tsx +++ b/editor/pages/figma/inspect-frame.tsx @@ -24,8 +24,8 @@ export default function InspectAutolayout() { ); diff --git a/editor/pages/figma/inspect-raw.tsx b/editor/pages/figma/inspect-raw.tsx index 7acd05a1..ece227dc 100644 --- a/editor/pages/figma/inspect-raw.tsx +++ b/editor/pages/figma/inspect-raw.tsx @@ -20,8 +20,8 @@ export default function InspectRaw() { ); diff --git a/editor/scaffolds/code/index.tsx b/editor/scaffolds/code/index.tsx index 207f3b24..11a41cf6 100644 --- a/editor/scaffolds/code/index.tsx +++ b/editor/scaffolds/code/index.tsx @@ -193,10 +193,11 @@ export function CodeSegment() { files={ code ? { - "index.tsx": { + // TODO: make this to match framework + "App.tsx": { raw: code.raw, language: framework_config.language, - name: "index.tsx", + name: "App.tsx", }, } : {