1
- import React , { useState , useEffect , useRef } from 'react' ;
1
+ import React , { useState , useEffect , useRef , useCallback } from 'react' ;
2
2
import { Box , Text , Link as ChakraLink , Heading , useColorModeValue , useColorMode } from '@chakra-ui/react' ;
3
3
import MonacoEditor from '@monaco-editor/react' ;
4
4
import ReactMarkdown from 'react-markdown' ;
5
5
import debounce from 'lodash/debounce' ;
6
6
7
+ function calculateChildrenHeight ( parentDiv ) {
8
+ let childrenHeight = 0 ;
9
+ const children = parentDiv . children ;
10
+ for ( let i = 0 ; i < children . length ; i ++ ) {
11
+ childrenHeight += children [ i ] . offsetHeight ;
12
+ }
13
+ return childrenHeight ;
14
+ }
15
+
7
16
const ChakraMarkdown = React . memo < any > ( ( { content } ) => {
8
- const { colorMode } = useColorMode ( ) ;
9
- const editorRef = useRef ( ) ;
10
- const monacoTheme = colorMode === 'dark' ? 'vs-dark' : 'vs-light' ;
11
- const [ editorHeight , setEditorHeight ] = useState ( 0 ) ;
12
17
const renderers = {
13
18
h1 : ( { children } ) => < Heading as = "h1" size = "xl" mb = { 2 } > { children } </ Heading > ,
14
19
h2 : ( { children } ) => < Heading as = "h2" size = "lg" mb = { 2 } > { children } </ Heading > ,
@@ -19,32 +24,88 @@ const ChakraMarkdown = React.memo<any>(({ content }) => {
19
24
</ ChakraLink >
20
25
) ,
21
26
code : ( { inline, children, className } ) => {
27
+ const { colorMode } = useColorMode ( ) ;
28
+ const monacoTheme = colorMode === 'dark' ? 'vs-dark' : 'vs-light' ;
29
+
30
+ const codeContainerRef = useRef ( null ) ;
31
+
32
+
33
+
22
34
const language = className ? className . replace ( 'language-' , '' ) : 'plaintext' ;
23
35
const code = String ( children ) . trim ( ) ;
36
+
37
+ const lines = code . split ( '\n' ) . length ;
38
+ const lineHeight = 18 ; // Approximate height of each line in pixels
39
+ // const horizonalScrollBarHeight = 12;
40
+ // const totalHeight = lines * lineHeight + horizonalScrollBarHeight;
41
+ const defaultHeight = lines * lineHeight ;
42
+ // setEditorHeight(`${totalHeight}px`);
43
+
44
+ const heightRef = useRef ( defaultHeight ) ;
45
+ const [ editorHeight , setEditorHeight ] = useState ( defaultHeight ) ;
46
+ heightRef . current = editorHeight ;
47
+
24
48
if ( inline ) {
25
49
return < Text as = "code" bg = { useColorModeValue ( "gray.100" , "gray.700" ) } p = "1" borderRadius = "md" > { code } </ Text > ;
26
50
}
51
+
52
+ const updateHeight = useCallback ( ( ) => {
53
+ // setEditorHeight(defaultHeight);
54
+ // setTimeout(() => {
55
+ const childrenHeight = calculateChildrenHeight ( codeContainerRef . current ) ;
56
+ const scrollHeight = codeContainerRef . current ?. scrollHeight ;
57
+ const offsetHeight = codeContainerRef . current ?. offsetHeight ;
58
+ // const newHeight = Math.max(childrenHeight);
59
+ console . log ( 'resize' , 'childrenHeight' , childrenHeight ) ;
60
+ console . log ( 'resize' , 'scrollHeight' , scrollHeight ) ;
61
+ console . log ( 'resize' , 'clientHeight' , codeContainerRef . current . clientHeight ) ;
62
+ console . log ( 'resize' , 'offsetHeight' , codeContainerRef . current . offsetHeight ) ;
63
+ console . log ( 'resize' , 'editorHeight' , heightRef . current ) ;
64
+
65
+ // if (editorHeight < childrenHeight) {
66
+ // setEditorHeight(childrenHeight);
67
+ // } else {
68
+ // const scrollHeight = codeContainerRef.current?.scrollHeight;
69
+ // const offsetHeight = codeContainerRef.current?.offsetHeight;
70
+ // const newHeight = Math.max(childrenHeight, scrollHeight, offsetHeight);
71
+ // setEditorHeight(newHeight);
72
+ // }
73
+ // if (newHeight > defaultHeight && editorHeight !== newHeight) {
74
+
75
+ // }
76
+
77
+ if ( heightRef . current <= childrenHeight ) {
78
+ const newHeight = Math . max ( childrenHeight , scrollHeight ) ;
79
+ setEditorHeight ( newHeight ) ;
80
+ } else {
81
+ const newHeight = Math . min ( childrenHeight , scrollHeight ) ;
82
+ setEditorHeight ( newHeight ) ;
83
+ }
84
+
85
+
86
+ // const scrollHeight = codeContainerRef.current?.scrollHeight;
87
+ // console.log('resize', 'scrollHeight', scrollHeight);
88
+ // setEditorHeight(scrollHeight);
89
+
90
+ // }, 0);
91
+ } , [ editorHeight ] ) ;
92
+
27
93
useEffect ( ( ) => {
28
- const lines = code . split ( '\n' ) . length ;
29
- const lineHeight = 18 ; // Approximate height of each line in pixels
30
- // const horizonalScrollBarHeight = 12;
31
- // const totalHeight = lines * lineHeight + horizonalScrollBarHeight;
32
- const totalHeight = lines * lineHeight ;
33
- // setEditorHeight(`${totalHeight}px`);
34
- } , [ children ] ) ;
94
+ return ( ) => {
95
+ window . removeEventListener ( 'resize' , updateHeight ) ;
96
+ console . log ( 'unmount' ) ;
97
+ // updateHeight.cancel(); // Cancels the debounced function
98
+ } ;
99
+ } , [ ] ) ;
35
100
return (
36
101
< Box
37
102
border = "1px solid"
38
103
borderColor = { useColorModeValue ( "gray.200" , "gray.600" ) }
39
104
borderRadius = "0"
40
105
overflow = "visible"
41
- onResize = { ( ) => {
42
- console . log ( 'resize' ) ;
43
- setEditorHeight ( 0 ) ;
44
- } }
45
- my = { 2 } >
106
+ my = { 2 }
107
+ >
46
108
< MonacoEditor
47
-
48
109
height = { editorHeight }
49
110
language = { language }
50
111
theme = { monacoTheme }
@@ -55,16 +116,15 @@ const ChakraMarkdown = React.memo<any>(({ content }) => {
55
116
scrollBeyondLastLine : false ,
56
117
lineNumbers : "off" ,
57
118
scrollbar : { vertical : 'hidden' } ,
58
- overviewRulerLanes : 0 , // Disable the overview ruler
59
- hideCursorInOverviewRuler : true , // Hide cursor in the ruler
60
- folding : false , // Disable code folding
61
- glyphMargin : false , // Hide the glyph margin (left margin with icons)
62
- renderLineHighlight : 'none' , // Disable the current line highlight
119
+ overviewRulerLanes : 0 ,
120
+ hideCursorInOverviewRuler : true ,
121
+ folding : false ,
122
+ glyphMargin : false ,
123
+ renderLineHighlight : 'none' ,
63
124
cursorWidth : 1 ,
64
125
wordWrap : 'on' ,
65
126
} }
66
- onMount = { ( editor , monaco ) => {
67
- console . log ( 'mount' ) ;
127
+ onMount = { ( editor ) => {
68
128
const keepIds = [ "editor.action.clipboardCopyAction" ] ;
69
129
const contextmenu = editor . getContribution ( 'editor.contrib.contextmenu' ) ;
70
130
const realMethod = contextmenu . _getMenuActions ;
@@ -75,65 +135,35 @@ const ChakraMarkdown = React.memo<any>(({ content }) => {
75
135
} ) ;
76
136
} ;
77
137
78
- console . log ( 'editor' , editor ) ;
79
- const el = editor . _domElement ;
80
- console . log ( 'el' , el ) ;
81
- const codeContainer = el ?. querySelector ?.( '.view-lines' ) ;
82
- console . log ( 'codeContainer' , codeContainer ) ;
83
-
84
-
85
- let prevLineCount = 0 ;
86
-
87
- const LINE_HEIGHT = 18 ;
88
- const CONTAINER_GUTTER = 10 ;
89
-
90
- window . addEventListener ( 'resize' , debounce ( function ( event ) {
91
- // Your code here
92
- // console.log('Window resized to: ', window.innerWidth, window.innerHeight);
93
- // const lines = code.split('\n').length;
94
- // const lineHeight = 18; // Approximate height of each line in pixels
95
- // // const horizonalScrollBarHeight = 12;
96
- // // const totalHeight = lines * lineHeight + horizonalScrollBarHeight;
97
- // const totalHeight = lines * lineHeight;
98
- // if (editorHeight === totalHeight) {
99
- // setEditorHeight(totalHeight-lineHeight); // Force change
100
- // } else {
101
- // setEditorHeight(totalHeight);
102
- // }
103
-
104
- if ( codeContainer . offsetHeight > 0 ) {
105
- // el.style.height = codeContainer.offsetHeight + 'px';
106
- const newHeight = codeContainer . offsetHeight ;
107
- if ( editorHeight !== newHeight ) {
108
- setEditorHeight ( newHeight ) ;
109
- }
110
- // editor.layout();
111
- }
112
- } , 200 ) ) ;
113
-
114
- editor . onDidChangeModelDecorations ( ( ) => {
115
- // wait until dom rendered
116
- setTimeout ( ( ) => {
117
- console . log ( 'codeContainer.offsetHeight' , codeContainer ?. offsetHeight ) ;
118
- if ( codeContainer . offsetHeight > 0 ) {
119
- // el.style.height = codeContainer.offsetHeight + 'px';
120
- const newHeight = codeContainer . offsetHeight ;
121
- setEditorHeight ( newHeight ) ;
122
- // editor.layout();
123
- }
124
- // const height =
125
- // codeContainer.childElementCount > prevLineCount
126
- // ? codeContainer.offsetHeight // unfold
127
- // : codeContainer.childElementCount * LINE_HEIGHT + CONTAINER_GUTTER; // fold
128
- // prevLineCount = codeContainer.childElementCount;
129
- } , 10 ) ;
138
+ const codeContainer = editor . _domElement ?. querySelector ( '.view-lines' ) ;
139
+ codeContainerRef . current = codeContainer ; // Assign the ref
140
+ // if (codeContainer?.offsetHeight > 0) {
141
+ // setEditorHeight(codeContainer.offsetHeight);
142
+ // }
143
+
144
+ console . log ( editor ) ;
145
+
146
+ window . addEventListener ( 'resize' , updateHeight ) ;
147
+
148
+ const eventHandler = editor . onDidChangeModelDecorations ( ( ) => {
149
+ const childrenHeight = calculateChildrenHeight ( codeContainerRef . current ) ;
150
+ const scrollHeight = codeContainerRef . current ?. scrollHeight ;
151
+ const offsetHeight = codeContainerRef . current ?. offsetHeight ;
152
+ const newHeight = Math . max ( childrenHeight , scrollHeight , offsetHeight ) ;
153
+ console . log ( 'onmount' , 'childrenHeight' , childrenHeight ) ;
154
+ console . log ( 'onmount' , 'scrollHeight' , scrollHeight ) ;
155
+ console . log ( 'onmount' , 'clientHeight' , codeContainerRef . current . clientHeight ) ;
156
+ console . log ( 'onmount' , 'offsetHeight' , codeContainerRef . current . offsetHeight ) ;
157
+ setEditorHeight ( newHeight ) ;
158
+ eventHandler . dispose ( ) ;
130
159
} ) ;
131
160
} }
132
161
/>
133
162
</ Box >
134
163
) ;
135
164
} ,
136
165
} ;
166
+
137
167
return < ReactMarkdown components = { renderers } children = { content } /> ;
138
168
} ) ;
139
169
0 commit comments