From 35cef50e44430241e7181ca4ced4de626397f02b Mon Sep 17 00:00:00 2001 From: David Lechner Date: Tue, 29 Nov 2022 16:02:25 -0600 Subject: [PATCH] editor: drop use of react-monaco-editor The upstream package is currently broken and doesn't actually save us any work. --- package.json | 4 +- src/editor/Editor.test.tsx | 2 +- src/editor/Editor.tsx | 70 +++++++++++++++---------------- src/editor/editor.scss | 6 +++ src/editor/lib.test.ts | 2 +- src/editor/lib.ts | 2 +- src/editor/pybricksMicroPython.ts | 2 +- src/editor/sagas.test.ts | 2 +- src/editor/sagas.ts | 2 +- src/editor/untitledHint.ts | 2 +- src/fileStorage/actions.ts | 2 +- src/fileStorage/index.ts | 2 +- src/hub/sagas.test.ts | 2 - src/monaco-extension.d.ts | 18 ++++---- yarn.lock | 14 ------- 15 files changed, 59 insertions(+), 73 deletions(-) diff --git a/package.json b/package.json index 50283c7c..6ac3a25a 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,6 @@ "react-dom": "^16.13.1", "react-dropzone": "^14.2.3", "react-joyride": "^2.5.3", - "react-monaco-editor": "^0.50.1", "react-popper": "^2.3.0", "react-redux": "^8.0.5", "react-refresh": "^0.14.0", @@ -198,11 +197,12 @@ "^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)": "/config/jest/fileTransform.mjs" }, "transformIgnorePatterns": [ - "[/\\\\]node_modules[/\\\\](?!(monaco-editor|react-monaco-editor|nanoevents)[/\\\\]).+\\.(js|jsx|mjs|cjs|ts|tsx)$", + "[/\\\\]node_modules[/\\\\](?!(monaco-editor|nanoevents)[/\\\\]).+\\.(js|jsx|mjs|cjs|ts|tsx)$", "^.+\\.module\\.(css|sass|scss)$" ], "modulePaths": [], "moduleNameMapper": { + "^monaco-editor$": "monaco-editor/esm/vs/editor/editor.api", "^react-native$": "react-native-web", "^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy" }, diff --git a/src/editor/Editor.test.tsx b/src/editor/Editor.test.tsx index ca1484a2..8204b1ba 100644 --- a/src/editor/Editor.test.tsx +++ b/src/editor/Editor.test.tsx @@ -3,8 +3,8 @@ import { Classes } from '@blueprintjs/core'; import { cleanup, fireEvent, waitFor } from '@testing-library/react'; +import * as monaco from 'monaco-editor'; import React from 'react'; -import { monaco } from 'react-monaco-editor'; import { testRender, uuid } from '../../test'; import { FileMetadata } from '../fileStorage'; import { useFileStorageMetadata, useFileStoragePath } from '../fileStorage/hooks'; diff --git a/src/editor/Editor.tsx b/src/editor/Editor.tsx index 5c59b44b..ef228688 100644 --- a/src/editor/Editor.tsx +++ b/src/editor/Editor.tsx @@ -16,17 +16,13 @@ import { Text, } from '@blueprintjs/core'; import { ContextMenu2, ResizeSensor2 } from '@blueprintjs/popover2'; +import * as monaco from 'monaco-editor'; import tomorrowNightEightiesTheme from 'monaco-themes/themes/Tomorrow-Night-Eighties.json'; import xcodeTheme from 'monaco-themes/themes/Xcode_default.json'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useId } from 'react-aria'; -import MonacoEditor, { - EditorDidMount, - EditorWillUnmount, - monaco, -} from 'react-monaco-editor'; import { useDispatch } from 'react-redux'; -import { useTernaryDarkMode } from 'usehooks-ts'; +import { useEffectOnce, useTernaryDarkMode } from 'usehooks-ts'; import { UUID } from '../fileStorage'; import { useFileStoragePath } from '../fileStorage/hooks'; import { compile } from '../mpy/actions'; @@ -364,18 +360,9 @@ const Editor: React.VFC = () => { const i18n = useI18n(); - const options = useMemo( - () => ({ - model: null, - fontSize: 18, - minimap: { enabled: false }, - contextmenu: false, - rulers: [80], - lineNumbersMinChars: 4, - wordBasedSuggestions: false, - }), - [], - ); + useEffect(() => { + monaco.editor.setTheme(isDarkMode ? tomorrowNightEightiesId : xcodeId); + }, [isDarkMode]); useEditor( editor, @@ -429,18 +416,6 @@ const Editor: React.VFC = () => { [], ); - const handleEditorDidMount = useCallback( - (editor) => { - editor.focus(); - setEditor(editor); - }, - [setEditor], - ); - - const handleEditorWillUnmount = useCallback(() => { - setEditor(undefined); - }, [setEditor]); - const popoverProps = useMemo( () => ({ onOpened: (e) => { @@ -462,6 +437,34 @@ const Editor: React.VFC = () => { [editor], ); + const editorRef = useRef(null); + + useEffectOnce(() => { + // istanbul ignore if: should never happen + if (!editorRef.current) { + console.error('no editorRef!'); + return; + } + + const monacoEditor = monaco.editor.create(editorRef.current, { + model: null, + fontSize: 18, + minimap: { enabled: false }, + contextmenu: false, + rulers: [80], + lineNumbersMinChars: 4, + wordBasedSuggestions: false, + }); + + monacoEditor.focus(); + setEditor(monacoEditor); + + return () => { + setEditor(undefined); + monacoEditor.dispose(); + }; + }); + return (
editor?.focus()} /> @@ -475,12 +478,7 @@ const Editor: React.VFC = () => { content={() => } popoverProps={popoverProps} > - +
diff --git a/src/editor/editor.scss b/src/editor/editor.scss index 3618b087..9d05540c 100644 --- a/src/editor/editor.scss +++ b/src/editor/editor.scss @@ -26,6 +26,7 @@ justify-content: flex-start; &-tablist { + flex: none; padding: bp.$pt-grid-size * 0.3; overflow-x: auto; @include pb.background-contrast(6%); @@ -63,6 +64,11 @@ flex: 1 1 auto; } + &-monaco { + width: 100%; + height: 100%; + } + &-placeholder { pointer-events: none; width: max-content; diff --git a/src/editor/lib.test.ts b/src/editor/lib.test.ts index aff1d966..719f475b 100644 --- a/src/editor/lib.test.ts +++ b/src/editor/lib.test.ts @@ -2,7 +2,7 @@ // Copyright (c) 2022 The Pybricks Authors import { mock } from 'jest-mock-extended'; -import type { monaco } from 'react-monaco-editor'; +import type * as monaco from 'monaco-editor'; import { uuid } from '../../test'; import { ActiveFileHistoryManager, OpenFileInfo, OpenFileManager } from './lib'; diff --git a/src/editor/lib.ts b/src/editor/lib.ts index a2568887..46d1f212 100644 --- a/src/editor/lib.ts +++ b/src/editor/lib.ts @@ -2,7 +2,7 @@ // Copyright (c) 2022 The Pybricks Authors import dexieObservable from 'dexie-observable'; -import type { monaco } from 'react-monaco-editor'; +import type * as monaco from 'monaco-editor'; import { UUID } from '../fileStorage'; // HACK: Using window.name to detect page reloads vs. tab duplication. diff --git a/src/editor/pybricksMicroPython.ts b/src/editor/pybricksMicroPython.ts index 863368f2..7b6c7f12 100644 --- a/src/editor/pybricksMicroPython.ts +++ b/src/editor/pybricksMicroPython.ts @@ -5,7 +5,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import type { monaco } from 'react-monaco-editor'; +import type * as monaco from 'monaco-editor'; /** The Pybricks MicroPython language identifier. */ export const pybricksMicroPythonId = 'pybricks-micropython'; diff --git a/src/editor/sagas.test.ts b/src/editor/sagas.test.ts index ce87f445..eb24cdbc 100644 --- a/src/editor/sagas.test.ts +++ b/src/editor/sagas.test.ts @@ -2,7 +2,7 @@ // Copyright (c) 2022 The Pybricks Authors import { mock } from 'jest-mock-extended'; -import { monaco } from 'react-monaco-editor'; +import * as monaco from 'monaco-editor'; import { AsyncSaga, uuid } from '../../test'; import { fileStorageDidFailToLoadTextFile, diff --git a/src/editor/sagas.ts b/src/editor/sagas.ts index 422f21b2..b83bdf89 100644 --- a/src/editor/sagas.ts +++ b/src/editor/sagas.ts @@ -2,7 +2,7 @@ // Copyright (c) 2022 The Pybricks Authors import type { DatabaseChangeType, IDatabaseChange } from 'dexie-observable/api'; -import { monaco } from 'react-monaco-editor'; +import * as monaco from 'monaco-editor'; import { EventChannel, buffers, eventChannel } from 'redux-saga'; import { call, diff --git a/src/editor/untitledHint.ts b/src/editor/untitledHint.ts index fb7d9c99..9b11ffc9 100644 --- a/src/editor/untitledHint.ts +++ b/src/editor/untitledHint.ts @@ -4,7 +4,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import type { monaco } from 'react-monaco-editor'; +import type * as monaco from 'monaco-editor'; export class UntitledHintContribution implements monaco.editor.IEditorContribution { public static readonly ID = 'editor.contrib.untitledHint'; diff --git a/src/fileStorage/actions.ts b/src/fileStorage/actions.ts index 7fabb305..09f01e0a 100644 --- a/src/fileStorage/actions.ts +++ b/src/fileStorage/actions.ts @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // Copyright (c) 2022 The Pybricks Authors -import type { monaco } from 'react-monaco-editor'; +import type * as monaco from 'monaco-editor'; import { createAction } from '../actions'; import { FileMetadata, UUID } from '.'; diff --git a/src/fileStorage/index.ts b/src/fileStorage/index.ts index 51e25b11..cdbd21f6 100644 --- a/src/fileStorage/index.ts +++ b/src/fileStorage/index.ts @@ -3,7 +3,7 @@ import 'dexie-observable'; import Dexie, { Table } from 'dexie'; -import type { monaco } from 'react-monaco-editor'; +import type * as monaco from 'monaco-editor'; /** Type to avoid mixing UUID with regular string. */ export type UUID = string & { _uuidBrand: undefined }; diff --git a/src/hub/sagas.test.ts b/src/hub/sagas.test.ts index 52bde2a9..b5877d53 100644 --- a/src/hub/sagas.test.ts +++ b/src/hub/sagas.test.ts @@ -22,8 +22,6 @@ import { } from './actions'; import hub from './sagas'; -jest.mock('react-monaco-editor'); - describe('downloadAndRun', () => { test('no errors', async () => { const saga = new AsyncSaga(hub, { diff --git a/src/monaco-extension.d.ts b/src/monaco-extension.d.ts index e8520fd0..2ff23cc8 100644 --- a/src/monaco-extension.d.ts +++ b/src/monaco-extension.d.ts @@ -3,17 +3,15 @@ // exposes some monaco editor internal functions -import {} from 'react-monaco-editor'; +import {} from 'monaco-editor'; -declare module 'react-monaco-editor' { - export namespace monaco { - export namespace editor { - export interface ITextModel { - // https://github.com/microsoft/vscode/blob/d54c705f6567958a732ac88b1c3ec4d2303fb026/src/vs/editor/common/model.ts#L1135 - canUndo: () => boolean; - // https://github.com/microsoft/vscode/blob/d54c705f6567958a732ac88b1c3ec4d2303fb026/src/vs/editor/common/model.ts#L1148 - canRedo: () => boolean; - } +declare module 'monaco-editor' { + export namespace editor { + export interface ITextModel { + // https://github.com/microsoft/vscode/blob/d54c705f6567958a732ac88b1c3ec4d2303fb026/src/vs/editor/common/model.ts#L1135 + canUndo: () => boolean; + // https://github.com/microsoft/vscode/blob/d54c705f6567958a732ac88b1c3ec4d2303fb026/src/vs/editor/common/model.ts#L1148 + canRedo: () => boolean; } } } diff --git a/yarn.lock b/yarn.lock index 6f285289..a45a3319 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2507,7 +2507,6 @@ __metadata: react-dom: ^16.13.1 react-dropzone: ^14.2.3 react-joyride: ^2.5.3 - react-monaco-editor: ^0.50.1 react-popper: ^2.3.0 react-redux: ^8.0.5 react-refresh: ^0.14.0 @@ -13028,19 +13027,6 @@ __metadata: languageName: node linkType: hard -"react-monaco-editor@npm:^0.50.1": - version: 0.50.1 - resolution: "react-monaco-editor@npm:0.50.1" - dependencies: - prop-types: ^15.8.1 - peerDependencies: - "@types/react": ">=17 <= 18" - monaco-editor: ^0.34.0 - react: ">=17 <= 18" - checksum: 509a9675bc878adb515d93c4cbfac1b1818f5cf54505aa50a40d9e848e9c243a75257c1ab13b505a9d8cbdbb2b09f90117bcf618e2d1ec1ffe2bf22fd16a3a03 - languageName: node - linkType: hard - "react-popper@npm:^1.3.11": version: 1.3.11 resolution: "react-popper@npm:1.3.11"