import * as React from 'react' ; export interface ReactMonacoEditorProps { width ? : string | number ; height ? : string | number ; value ? : string ; defaultValue ? : string ; language ? : string ; theme ? : string ; options ? : monaco . editor . IEditorOptions ; editorDidMount ? : ( monacoModule : typeof monaco , editor ? : monaco . editor . ICodeEditor ) => void ; editorWillMount ? : ( monacoModule : typeof monaco ) => void ; onChange ? : ( val : string , ev : monaco . editor . IModelContentChangedEvent ) => void ; requireConfig ? : { url ? : string ; paths ? : { vs ? : string ; } ; } ; context ? : any ; } interface ReactMonacoEditorState { containerElement ? : HTMLDivElement ; currentValue ? : string ; editor ? : monaco . editor . ICodeEditor ; preventTriggerChangeEvent ? : boolean ; } export default class MonacoEditor extends React . Component < ReactMonacoEditorProps , ReactMonacoEditorState > { constructor ( props ) { super ( props ) ; this . setState ( { containerElement : undefined } ) ; this . setState ( { currentValue : props . value } ) ; } componentDidMount ( ) { this . afterViewInit ( ) ; } componentDidUpdate ( prevProps ) { if ( this . props . value !== this . state . currentValue ) { this . setState ( { currentValue : this . props . value } ) ; if ( this . state . editor ) { this . setState ( { preventTriggerChangeEvent : true } ) ; this . state . editor . setValue ( this . props . value || '' ) ; this . setState ( { preventTriggerChangeEvent : false } ) ; } } } componentWillUnmount ( ) { this . destroyMonaco ( ) ; } editorWillMount ( mon ) { const { editorWillMount } = this . props ; if ( editorWillMount !== undefined ) { editorWillMount ( mon ) ; } } editorDidMount ( mon , editor ? ) { if ( this . props . editorDidMount !== undefined ) { this . props . editorDidMount ( monaco , editor ) ; } if ( editor !== undefined ) { editor . onDidChangeModelContent ( ( event ) => { const value = editor . getValue ( ) ; this . setState ( { currentValue : value } ) ; if ( ! this . state . preventTriggerChangeEvent ) { if ( this . props . onChange !== undefined ) { this . props . onChange ( value , event ) ; } } } ) ; } } afterViewInit ( ) { const context = this . props . context || window ; if ( context . monaco !== undefined ) { this . initMonaco ( ) ; return ; } const { requireConfig = { } } = this . props ; const inElectron = context . process && context . process . type === 'renderer' ; const loaderUrl = requireConfig !== undefined && requireConfig . url !== undefined ? requireConfig . url : 'vs/loader.js' ; if ( inElectron ) { context . electronNodeRequire = context . require ; } const onGotAmdLoader = ( ) => { if ( context . __REACT_MONACO_EDITOR_LOADER_ISPENDING__ ) { if ( inElectron ) { const path = context . electronNodeRequire ( 'path' ) ; function uriFromPath ( _path ) { let pathName = path . resolve ( _path ) . replace ( /\\/g , '/' ) ; if ( pathName . length > 0 && pathName . charAt ( 0 ) !== '/' ) { pathName = `/${ pathName }` ; } return encodeURI ( `file://${ pathName }` ) ; } const monacoPath = path . join ( context . __dirname , 'dist/monaco-editor/min' ) ; const amdRequireBaseUrl = uriFromPath ( monacoPath ) ; context . require . config ( { baseUrl : amdRequireBaseUrl , } ) ; context . window . module = undefined ; context . window . process . browser = true ; } if ( requireConfig . paths && requireConfig . paths . vs ) { context . require . config ( requireConfig ) ; } } context . require ( [ 'vs/editor/editor.main' ] , ( ) => { this . initMonaco ( ) ; } ) ; if ( context . __REACT_MONACO_EDITOR_LOADER_ISPENDING__ ) { context . __REACT_MONACO_EDITOR_LOADER_ISPENDING__ = false ; const loaderCallbacks = context . __REACT_MONACO_EDITOR_LOADER_CALLBACKS__ ; if ( loaderCallbacks && loaderCallbacks . length ) { let currentCallback = loaderCallbacks . shift ( ) ; while ( currentCallback ) { currentCallback . fn . call ( currentCallback . context ) ; currentCallback = loaderCallbacks . shift ( ) ; } } } } ; if ( context . __REACT_MONACO_EDITOR_LOADER_ISPENDING__ ) { context . __REACT_MONACO_EDITOR_LOADER_CALLBACKS__ = context . __REACT_MONACO_EDITOR_LOADER_CALLBACKS__ || [ ] ; context . __REACT_MONACO_EDITOR_LOADER_CALLBACKS__ . push ( { context : this , fn : onGotAmdLoader , } ) ; } else if ( typeof context . require === 'undefined' || inElectron ) { const loaderScript = context . document . createElement ( 'script' ) ; loaderScript . type = 'text/javascript' ; loaderScript . src = loaderUrl ; loaderScript . addEventListener ( 'load' , onGotAmdLoader ) ; context . document . body . appendChild ( loaderScript ) ; context . __REACT_MONACO_EDITOR_LOADER_ISPENDING__ = true ; } else { onGotAmdLoader ( ) ; } } initMonaco ( ) { const value = this . props . value !== null ? this . props . value : this . props . defaultValue ; const { language = 'javascript' , theme = undefined , options = { } } = this . props ; const context = this . props . context || window ; if ( this . state . containerElement && typeof context . monaco !== 'undefined' ) { this . editorWillMount ( context . monaco ) ; this . setState ( { editor : context . monaco . editor . create ( this . state . containerElement , { value , language , ... options , } ) , } ) ; if ( theme ) { context . monaco . editor . setTheme ( theme ) ; } this . editorDidMount ( context . monaco , this . state . editor ) ; } } destroyMonaco ( ) { if ( typeof this . state . editor !== 'undefined' ) { this . state . editor . dispose ( ) ; } } assignRef = ( component ) => { this . setState ( { containerElement : component } ) ; } ; render ( ) { const { width = '100%' , height = '100%' } = this . props ; const fixedWidth = width . toString ( ) . indexOf ( '%' ) !== - 1 ? width : `${ width }px` ; const fixedHeight = height . toString ( ) . indexOf ( '%' ) !== - 1 ? height : `${ height }px` ; const style = { width : fixedWidth , height : fixedHeight , } ; return < div ref = { this . assignRef } style = { style } className = 'react-monaco-editor-container' / > ; } }