1
+ import React , { useRef , useState , useEffect } from 'react' ;
2
+ import { Box , useColorMode } from '@chakra-ui/react' ;
3
+ import MonacoEditor from '@monaco-editor/react' ;
4
+
5
+ interface MonacoMarkdownEditorProps {
6
+ value : string ;
7
+ onChange : ( value : string ) => void ;
8
+ onEnter ?: ( ) => void ;
9
+ placeholder ?: string ;
10
+ maxHeight ?: string ;
11
+ minHeight ?: string ;
12
+ }
13
+
14
+ const MonacoMarkdownEditor : React . FC < MonacoMarkdownEditorProps > = ( {
15
+ value,
16
+ onChange,
17
+ onEnter,
18
+ placeholder = "Type your message with Markdown..." ,
19
+ maxHeight = "30vh" ,
20
+ minHeight = "100px"
21
+ } ) => {
22
+ const { colorMode } = useColorMode ( ) ;
23
+ const editorRef = useRef ( null ) ;
24
+ const [ editorHeight , setEditorHeight ] = useState ( minHeight ) ;
25
+
26
+ const monacoTheme = colorMode === 'dark' ? 'vs-dark' : 'vs-light' ;
27
+
28
+ // Auto-resize editor based on content
29
+ const updateEditorHeight = ( ) => {
30
+ if ( editorRef . current ) {
31
+ const editor = editorRef . current ;
32
+ const contentHeight = editor . getContentHeight ( ) ;
33
+ const maxHeightPx = parseInt ( maxHeight . replace ( 'vh' , '' ) ) * window . innerHeight / 100 ;
34
+ const minHeightPx = parseInt ( minHeight . replace ( 'px' , '' ) ) ;
35
+
36
+ const newHeight = Math . min ( Math . max ( contentHeight , minHeightPx ) , maxHeightPx ) ;
37
+ setEditorHeight ( `${ newHeight } px` ) ;
38
+ }
39
+ } ;
40
+
41
+ const handleEditorDidMount = ( editor , monaco ) => {
42
+ editorRef . current = editor ;
43
+
44
+ // Set up auto-resize
45
+ editor . onDidContentSizeChange ( updateEditorHeight ) ;
46
+
47
+ // Initial height calculation
48
+ updateEditorHeight ( ) ;
49
+
50
+ // Configure editor for better markdown editing experience
51
+ editor . updateOptions ( {
52
+ automaticLayout : true ,
53
+ scrollBeyondLastLine : false ,
54
+ wordWrap : 'on' ,
55
+ minimap : { enabled : false } ,
56
+ lineNumbers : 'off' ,
57
+ folding : false ,
58
+ selectOnLineNumbers : false ,
59
+ overviewRulerLanes : 0 ,
60
+ hideCursorInOverviewRuler : true ,
61
+ renderLineHighlight : 'none' ,
62
+ scrollbar : {
63
+ vertical : 'auto' ,
64
+ horizontal : 'auto' ,
65
+ verticalScrollbarSize : 8 ,
66
+ horizontalScrollbarSize : 8
67
+ }
68
+ } ) ;
69
+
70
+ // Show placeholder when empty
71
+ if ( ! value ) {
72
+ editor . setValue ( '' ) ;
73
+ }
74
+
75
+ // Add keyboard shortcut for Enter to send (Ctrl+Enter for new line)
76
+ if ( onEnter ) {
77
+ editor . addCommand ( monaco . KeyMod . CtrlCmd | monaco . KeyCode . Enter , ( ) => {
78
+ // Ctrl+Enter adds new line (default behavior)
79
+ editor . trigger ( 'keyboard' , 'type' , { text : '\n' } ) ;
80
+ } ) ;
81
+
82
+ editor . addCommand ( monaco . KeyCode . Enter , ( ) => {
83
+ // Enter sends message
84
+ onEnter ( ) ;
85
+ } ) ;
86
+ }
87
+ } ;
88
+
89
+ const handleEditorChange = ( newValue ) => {
90
+ onChange ( newValue || '' ) ;
91
+ // Trigger height update after content change
92
+ setTimeout ( updateEditorHeight , 0 ) ;
93
+ } ;
94
+
95
+ useEffect ( ( ) => {
96
+ updateEditorHeight ( ) ;
97
+ } , [ value ] ) ;
98
+
99
+ return (
100
+ < Box
101
+ border = "1px solid"
102
+ borderColor = { colorMode === 'dark' ? 'gray.600' : 'gray.200' }
103
+ borderRadius = "md"
104
+ overflow = "hidden"
105
+ flex = "1"
106
+ >
107
+ < MonacoEditor
108
+ height = { editorHeight }
109
+ language = "markdown"
110
+ theme = { monacoTheme }
111
+ value = { value }
112
+ onChange = { handleEditorChange }
113
+ onMount = { handleEditorDidMount }
114
+ options = { {
115
+ placeholder : placeholder ,
116
+ automaticLayout : true ,
117
+ scrollBeyondLastLine : false ,
118
+ wordWrap : 'on' ,
119
+ minimap : { enabled : false } ,
120
+ lineNumbers : 'off' ,
121
+ folding : false ,
122
+ selectOnLineNumbers : false ,
123
+ overviewRulerLanes : 0 ,
124
+ hideCursorInOverviewRuler : true ,
125
+ renderLineHighlight : 'none' ,
126
+ scrollbar : {
127
+ vertical : 'auto' ,
128
+ horizontal : 'auto' ,
129
+ verticalScrollbarSize : 8 ,
130
+ horizontalScrollbarSize : 8
131
+ } ,
132
+ fontSize : 14 ,
133
+ fontFamily : 'ui-monospace, SFMono-Regular, "Roboto Mono", monospace'
134
+ } }
135
+ />
136
+ </ Box >
137
+ ) ;
138
+ } ;
139
+
140
+ export default MonacoMarkdownEditor ;
0 commit comments