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