diff --git a/packages/ui-default/components/monaco/loader.ts b/packages/ui-default/components/monaco/loader.ts index 242ff1d58..15161eaa1 100644 --- a/packages/ui-default/components/monaco/loader.ts +++ b/packages/ui-default/components/monaco/loader.ts @@ -28,8 +28,13 @@ const loaders = { }, }; +let loadPromise = Promise.resolve(); + export async function load(features = ['markdown']) { let s = Date.now(); + await loadPromise; + let resolve; + loadPromise = new Promise((r) => { resolve = r; }); if (!loaded) { await loaders.i18n(); console.log('Loading monaco editor'); @@ -60,7 +65,8 @@ export async function load(features = ['markdown']) { } } await res.loadThemePromise; - return { monaco: res.default, registerAction: res.registerAction }; + resolve(); + return { monaco: res.default, registerAction: res.registerAction, customOptions: {} }; } export default load; diff --git a/packages/ui-default/components/scratchpad/ScratchpadEditorContainer.jsx b/packages/ui-default/components/scratchpad/ScratchpadEditorContainer.tsx similarity index 73% rename from packages/ui-default/components/scratchpad/ScratchpadEditorContainer.jsx rename to packages/ui-default/components/scratchpad/ScratchpadEditorContainer.tsx index ebf27871c..1ccbecd59 100644 --- a/packages/ui-default/components/scratchpad/ScratchpadEditorContainer.jsx +++ b/packages/ui-default/components/scratchpad/ScratchpadEditorContainer.tsx @@ -1,39 +1,49 @@ +import type * as monaco from 'monaco-editor'; import React from 'react'; import { connect } from 'react-redux'; import { load } from 'vj/components/monaco/loader'; -const mapStateToProps = (state) => ({ +interface ScratchpadOptions { + value?: string; + language?: string; + handleUpdateCode?: (str: string, event: monaco.editor.IModelContentChangedEvent) => void; + mainSize?: number; + recordSize?: number; + pretestSize?: number; +} + +export default connect((state: any) => ({ value: state.editor.code, language: window.LANGS[state.editor.lang]?.monaco, mainSize: state.ui.main.size, pretestSize: state.ui.pretest.size, recordSize: state.ui.records.size, -}); -const mapDispatchToProps = (dispatch) => ({ - handleUpdateCode: (code) => { +}), (dispatch) => ({ + handleUpdateCode: (code: string) => { dispatch({ type: 'SCRATCHPAD_EDITOR_UPDATE_CODE', payload: code, }); }, -}); - -export default connect(mapStateToProps, mapDispatchToProps)(class MonacoEditor extends React.PureComponent { +}))(class MonacoEditor extends React.PureComponent { disposable = []; + __prevent_trigger_change_event = false; + model: monaco.editor.ITextModel; + editor: monaco.editor.IStandaloneCodeEditor; + containerElement: HTMLElement; async componentDidMount() { const value = this.props.value || ''; const { language } = this.props; const { monaco, registerAction, customOptions } = await load([language]); const uri = monaco.Uri.parse(`hydro://${UiContext.pdoc.pid || UiContext.pdoc.docId}.${language}`); - this.model = monaco.editor.createModel(value, language, uri); + this.model = monaco.editor.getModel(uri) || monaco.editor.createModel(value, language, uri); if (this.containerElement) { - /** @type {monaco.editor.IStandaloneEditorConstructionOptions} */ - const config = { + const config: monaco.editor.IStandaloneEditorConstructionOptions = { theme: 'vs-light', ...customOptions, fontFamily: UserContext.codeFontFamily, - lineNumbers: true, + lineNumbers: 'on', glyphMargin: true, lightbulb: { enabled: true }, model: this.model, @@ -43,12 +53,12 @@ export default connect(mapStateToProps, mapDispatchToProps)(class MonacoEditor e this.disposable.push( this.editor.onDidChangeModelContent((event) => { if (!this.__prevent_trigger_change_event) { - this.props.handleUpdateCode(this.editor.getValue({ lineEnding: '\n', preserveBOM: false }), event); + this.props.handleUpdateCode?.(this.editor.getValue({ lineEnding: '\n', preserveBOM: false }), event); } }), ); - window.editor = this.editor; - window.monaco = monaco; + (window as any).editor = this.editor; + (window as any).monaco = monaco; window.Hydro.bus.emit('scratchpadEditorCreate', this.editor, monaco); } } @@ -71,6 +81,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(class MonacoEditor e text: value, }, ], + () => null, ); editor.pushUndoStop(); this.__prevent_trigger_change_event = false; @@ -79,7 +90,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(class MonacoEditor e const val = model.getValue(LF, false); model.dispose(); const uri = monaco.Uri.parse(`hydro://${UiContext.pdoc.pid || UiContext.pdoc.docId}.${language}`); - this.model = monaco.editor.createModel(val, language, uri); + this.model = monaco.editor.getModel(uri) || monaco.editor.createModel(val, language, uri); editor.setModel(this.model); } if (editor) { diff --git a/packages/ui-default/package.json b/packages/ui-default/package.json index c88262614..143704ca3 100644 --- a/packages/ui-default/package.json +++ b/packages/ui-default/package.json @@ -1,6 +1,6 @@ { "name": "@hydrooj/ui-default", - "version": "4.40.8", + "version": "4.40.11", "author": "undefined ", "license": "AGPL-3.0", "main": "hydro.js", diff --git a/packages/ui-default/types.ts b/packages/ui-default/types.ts index 207c28c12..c6859648d 100644 --- a/packages/ui-default/types.ts +++ b/packages/ui-default/types.ts @@ -1,6 +1,11 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -declare let UserContext: any; -declare let UiContext: any; -// eslint-disable-next-line -declare let node_modules: any; -declare let LANGS: Record; +declare global { + interface Window { + node_modules: any; + LANGS: Record; + } + + let UserContext: Record; + let UiContext: Record; +} + +export { };