1- import React , { useRef , useEffect } from "react" ;
2- import Editor , {
3- useMonaco ,
4- Monaco ,
5- OnMount ,
6- OnChange ,
7- } from "@monaco-editor/react" ;
1+ import React , { useRef } from "react" ;
2+ import Editor , { OnMount , OnChange } from "@monaco-editor/react" ;
83import * as monaco from "monaco-editor/esm/vs/editor/editor.api" ;
94import { MonacoEmptyMock } from "./monaco-mock-empty" ;
105import { register } from "./monaco-utils" ;
116import { __dangerous__lastFormattedValue__global } from "@code-editor/prettier-services" ;
7+ import { debounce } from "utils/debounce" ;
8+ import { downloadFile } from "utils/download" ;
129
1310type ICodeEditor = monaco . editor . IStandaloneCodeEditor ;
1411
1512export interface MonacoEditorProps {
16- defaultValue ?: string ;
17- defaultLanguage ?: string ;
13+ value ?: string ;
14+ language ?: string ;
1815 onChange ?: OnChange ;
1916 width ?: number | string ;
2017 height ?: number | string ;
@@ -23,16 +20,15 @@ export interface MonacoEditorProps {
2320
2421export function MonacoEditor ( props : MonacoEditorProps ) {
2522 const instance = useRef < { editor : ICodeEditor ; format : any } | null > ( null ) ;
26- const activeModel = useRef < any > ( ) ;
23+
24+ const path = "app." + lang2ext ( props . language ) ;
2725
2826 const onMount : OnMount = ( editor , monaco ) => {
2927 const format = editor . getAction ( "editor.action.formatDocument" ) ;
3028 const rename = editor . getAction ( "editor.action.rename" ) ;
3129
3230 instance . current = { editor, format } ;
3331
34- activeModel . current = editor . getModel ( ) ;
35-
3632 register . initEditor ( editor , monaco ) ;
3733
3834 editor . addCommand ( monaco . KeyMod . CtrlCmd | monaco . KeyCode . KeyS , function ( ) {
@@ -41,6 +37,7 @@ export function MonacoEditor(props: MonacoEditorProps) {
4137
4238 // disabled. todo: find a way to format on new line, but also with adding new line.
4339 // editor.addCommand(monaco.KeyCode.Enter, function () {
40+ // // add new line via script, then run format
4441 // format.run();
4542 // });
4643
@@ -50,9 +47,24 @@ export function MonacoEditor(props: MonacoEditorProps) {
5047 rename . run ( ) ;
5148 } ) ;
5249
53- editor . onDidChangeModelContent ( ( e ) => {
54- /* add here */
50+ editor . addAction ( {
51+ // An unique identifier of the contributed action.
52+ id : "export-module-as-file" ,
53+
54+ // A label of the action that will be presented to the user.
55+ label : "Export as file" ,
56+ precondition : null ,
57+ keybindingContext : null ,
58+ contextMenuGroupId : "navigation" ,
59+ contextMenuOrder : 1.5 ,
60+ run : function ( ed ) {
61+ downloadFile ( { data : ed . getModel ( ) . getValue ( ) , filename : path } ) ;
62+ } ,
5563 } ) ;
64+
65+ editor . onDidChangeModelContent ( ( ) =>
66+ debounce ( ( ) => editor . saveViewState ( ) , 200 )
67+ ) ;
5668 } ;
5769
5870 return (
@@ -61,11 +73,10 @@ export function MonacoEditor(props: MonacoEditorProps) {
6173 onMount = { onMount }
6274 width = { props . width }
6375 height = { props . height }
64- defaultLanguage = {
65- pollyfill_language ( props . defaultLanguage ) ?? "typescript"
66- }
76+ language = { pollyfill_language ( props . language ) ?? "typescript" }
77+ path = { path }
6778 loading = { < MonacoEmptyMock l = { 5 } /> }
68- defaultValue = { props . defaultValue ?? "// no content" }
79+ value = { props . value ?? "// no content" }
6980 theme = "vs-dark"
7081 onChange = { ( ...v ) => {
7182 if ( v [ 0 ] === __dangerous__lastFormattedValue__global ) {
@@ -84,6 +95,23 @@ export function MonacoEditor(props: MonacoEditorProps) {
8495 ) ;
8596}
8697
98+ const lang2ext = ( lang : string ) => {
99+ switch ( lang ) {
100+ case "typescript" :
101+ return "ts" ;
102+ case "javascript" :
103+ return "js" ;
104+ case "tsx" :
105+ return "tsx" ;
106+ case "jsx" :
107+ return "jsx" ;
108+ case "dart" :
109+ return "dart" ;
110+ default :
111+ return lang ;
112+ }
113+ } ;
114+
87115const pollyfill_language = ( lang : string ) => {
88116 switch ( lang ) {
89117 case "tsx" :
0 commit comments