11import React from 'react' ;
22import ReactDOM from 'react-dom' ;
3- import CodeMirror , { IReactCodemirror } from '@uiw/react-codemirror' ;
3+ import CodeMirror , { ReactCodeMirrorProps , ReactCodeMirrorRef , ViewUpdate } from '@uiw/react-codemirror' ;
44import copyTextToClipboard from '@uiw/copy-to-clipboard' ;
5+ import { javascript } from '@codemirror/lang-javascript' ;
56import { CodeSandboxProps } from '@uiw/react-codesandbox' ;
67import { CodepenProps } from '@uiw/react-codepen' ;
78import Split , { SplitProps } from '@uiw/react-split' ;
89import ThirdPartyButton from './ThirdPartyButton' ;
910import * as icon from './icon' ;
1011import { BabelTransform } from './transform' ;
12+ import { ErrorMessage } from './ErrorMessage' ;
1113import './monokai.css' ;
1214import './index.less' ;
1315
@@ -18,13 +20,6 @@ export interface CodePreviewProps extends SplitProps {
1820 * To specify a CSS class, use the className attribute.
1921 */
2022 className ?: string ;
21- /**
22- * string|object. The mode to use. When not given, this will default to the first mode that was loaded.
23- * It may be a string, which either simply names the mode or is a MIME type associated with the mode.
24- * Alternatively, it may be an object containing configuration options for the mode,
25- * with a name property that names the mode (for example `{name: "javascript", json: true}` ).
26- */
27- language ?: string | { name : string , json : boolean } ;
2823 /**
2924 * Whether to display the border.
3025 */
@@ -56,7 +51,7 @@ export interface CodePreviewProps extends SplitProps {
5651 /**
5752 * Modify ReactCodemirror props.
5853 */
59- editProps ?: IReactCodemirror ;
54+ editProps ?: ReactCodeMirrorProps ;
6055 /**
6156 * Dependent component
6257 */
@@ -75,24 +70,21 @@ export interface CodePreviewProps extends SplitProps {
7570 btnHideText ?: string ;
7671}
7772
78- export interface ICodePreviewState {
73+ export interface CodePreviewState {
7974 errorMessage : string ;
8075 fullScreen : boolean ;
8176 width : number | string ;
8277 copied : boolean ;
8378 showEdit : boolean ;
8479}
8580
86- export default class CodePreview extends React . PureComponent < CodePreviewProps , ICodePreviewState > {
81+ export default class CodePreview extends React . PureComponent < CodePreviewProps , CodePreviewState > {
8782 public demoDom = React . createRef < HTMLDivElement > ( ) ;
88- // @ts -ignore
89- public editor = React . createRef < CodeMirror > ( ) ;
90- public language : string = '' ;
83+ public editor = React . createRef < ReactCodeMirrorRef > ( ) ;
9184 public initHeight : number = 3 ;
9285 public playerId : string = `${ parseInt ( String ( Math . random ( ) * 1e9 ) , 10 ) . toString ( 36 ) } ` ;
9386 public static defaultProps : CodePreviewProps = {
9487 prefixCls : 'w-code-preview' ,
95- language : 'jsx' ,
9688 code : '' ,
9789 btnText : 'Code' ,
9890 btnHideText : 'Hide Editor' ,
@@ -104,36 +96,32 @@ export default class CodePreview extends React.PureComponent<CodePreviewProps, I
10496 noPreview : false ,
10597 bordered : true ,
10698 }
107- public state : ICodePreviewState = {
108- errorMessage : '' ,
109- fullScreen : false ,
110- copied : false ,
111- showEdit : false ,
112- width : 1 ,
99+ constructor ( props : CodePreviewProps ) {
100+ super ( props ) ;
101+ this . state = {
102+ errorMessage : '' ,
103+ fullScreen : false ,
104+ copied : false ,
105+ showEdit : false ,
106+ width : 1 ,
107+ }
113108 }
114109 componentDidMount ( ) {
115- const { language } = this . props ;
116- this . language = typeof language === 'string' ? language : ( language ? ( language . name || '' ) : '' ) ;
117110 if ( ! this . props . noPreview ) {
118111 this . executeCode ( this . props . code ! ) ;
119112 }
120- window . addEventListener ( "popstate" , function ( e ) {
113+ window . addEventListener ( "popstate" , ( e ) => {
121114 document . body . style . overflow = 'inherit' ;
122115 } , false ) ;
123116 }
124117 componentDidUpdate ( prevProps : CodePreviewProps ) {
125- const { language } = this . props ;
126- this . language = typeof language === 'string' ? language : ( language ? ( language . name || '' ) : '' ) ;
127118 if ( prevProps . noPreview !== this . props . noPreview ) {
128- this . executeCode ( this . props . code ! ) ;
119+ this . executeCode ( prevProps . code ! ) ;
129120 }
130121 }
131122 async executeCode ( codeStr : string ) {
132123 const { dependencies = { } } = this . props ;
133- const { React : _React , ReactDOM : _ReactDOM , ...otherDeps } = dependencies
134- if ( ! / ( j s x | j s ) / . test ( this . language ) ) {
135- return ;
136- }
124+ const { React : _React , ReactDOM : _ReactDOM , ...otherDeps } = dependencies ;
137125 try {
138126 const deps = {
139127 context : this ,
@@ -153,11 +141,11 @@ export default class CodePreview extends React.PureComponent<CodePreviewProps, I
153141 const input = `${ codeStr } ` ;
154142 const { code } = BabelTransform ( input ) ;
155143 args . push ( code || '' ) ;
144+ // console.log('code:', argv)
156145 // eslint-disable-next-line no-new-func
157146 new Function ( ...args ) . apply ( null , argv ) ;
158147 this . setState ( { errorMessage : '' } ) ;
159-
160- } catch ( err ) {
148+ } catch ( err : any ) {
161149 let message = '' ;
162150 if ( err && err . message ) {
163151 message = err . message ;
@@ -197,6 +185,13 @@ export default class CodePreview extends React.PureComponent<CodePreviewProps, I
197185 this . initHeight = demo . clientHeight ;
198186 }
199187 }
188+ handleChange ( value : string , viewUpdate : ViewUpdate ) {
189+ const { editProps } = this . props ;
190+ this . executeCode ( value ) ;
191+ if ( editProps && editProps . onChange ) {
192+ editProps . onChange ( value , viewUpdate ) ;
193+ }
194+ }
200195 /**
201196 * onSwitchSource
202197 */
@@ -206,14 +201,10 @@ export default class CodePreview extends React.PureComponent<CodePreviewProps, I
206201 this . setState ( {
207202 width : width === 1 ? '50%' : 1 ,
208203 showEdit : true ,
209- } , ( ) => {
210- if ( this . editor && this . editor . current && this . editor . current . editor ) {
211- this . editor . current . editor . setSize ( '100%' , width !== 1 ? this . initHeight : '100%' ) ;
212- }
213204 } ) ;
214205 }
215206 public render ( ) {
216- const { style, prefixCls, language , className, editProps, codePenOption, codeSandboxOption, code, dependencies, btnText, btnHideText, onlyEdit, bordered, noCode, noPreview, noScroll, bgWhite, ...otherProps } = this . props ;
207+ const { style, prefixCls, className, editProps, codePenOption, codeSandboxOption, code, dependencies, btnText, btnHideText, onlyEdit, bordered, noCode, noPreview, noScroll, bgWhite, ...otherProps } = this . props ;
217208 const isOneItem = ( ! noCode && ! noPreview ) ? false : ( ! noCode || ! noPreview ) ;
218209 let visiable = this . state . width === 1 ? false : [ isOneItem ? 1 : 2 ] ;
219210 return (
@@ -242,31 +233,21 @@ export default class CodePreview extends React.PureComponent<CodePreviewProps, I
242233 ...( this . state . width === 1 ? { width : '100%' } : { } )
243234 } }
244235 >
245- { this . state . errorMessage && (
246- < pre >
247- < code > { this . state . errorMessage } </ code >
248- </ pre >
249- ) }
236+ < ErrorMessage message = { this . state . errorMessage } />
250237 < div className = { [ `${ prefixCls } -demo-source` , this . state . errorMessage ? 'error' : null ] . filter ( Boolean ) . join ( ' ' ) . trim ( ) } id = { this . playerId } />
251238 </ div >
252239 ) }
253240 { ( ! noCode || onlyEdit ) && (
254- < div style = { { overflow : 'hidden' , width : onlyEdit ? '100%' : this . state . width , } } >
241+ < div style = { { overflow : 'hidden' , width : onlyEdit ? '100%' : this . state . width } } >
255242 { ( this . state . showEdit || onlyEdit ) && (
256243 < CodeMirror
257- value = { ( code || '' ) . replace ( / \n $ / , '' ) }
244+ value = { ( this . props . code || '' ) . replace ( / \n $ / , '' ) }
258245 ref = { this . editor }
259- options = { {
260- theme : 'monokai' ,
261- mode : language ,
262- } }
246+ extensions = { [ javascript ( { jsx : true } ) ] }
263247 { ...editProps }
264- onChange = { ( editor , change ) => {
265- this . executeCode ( editor . getValue ( ) ) ;
266- if ( editProps && editProps . onChange ) {
267- editProps . onChange ( editor , change )
268- }
269- } }
248+ style = { { height : '100%' } }
249+ height = "100%"
250+ onChange = { this . handleChange . bind ( this ) }
270251 />
271252 ) }
272253 </ div >
0 commit comments