Skip to content

Commit 728d519

Browse files
committed
First working prototype of fit to content height adjustment
1 parent cd48b7d commit 728d519

File tree

1 file changed

+107
-77
lines changed

1 file changed

+107
-77
lines changed

example/components/chakra-markdown.tsx

+107-77
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
1-
import React, { useState, useEffect, useRef } from 'react';
1+
import React, { useState, useEffect, useRef, useCallback } from 'react';
22
import { Box, Text, Link as ChakraLink, Heading, useColorModeValue, useColorMode } from '@chakra-ui/react';
33
import MonacoEditor from '@monaco-editor/react';
44
import ReactMarkdown from 'react-markdown';
55
import debounce from 'lodash/debounce';
66

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+
716
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);
1217
const renderers = {
1318
h1: ({ children }) => <Heading as="h1" size="xl" mb={2}>{children}</Heading>,
1419
h2: ({ children }) => <Heading as="h2" size="lg" mb={2}>{children}</Heading>,
@@ -19,32 +24,88 @@ const ChakraMarkdown = React.memo<any>(({ content }) => {
1924
</ChakraLink>
2025
),
2126
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+
2234
const language = className ? className.replace('language-', '') : 'plaintext';
2335
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+
2448
if (inline) {
2549
return <Text as="code" bg={useColorModeValue("gray.100", "gray.700")} p="1" borderRadius="md">{code}</Text>;
2650
}
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+
2793
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+
}, []);
35100
return (
36101
<Box
37102
border="1px solid"
38103
borderColor={useColorModeValue("gray.200", "gray.600")}
39104
borderRadius="0"
40105
overflow="visible"
41-
onResize={() => {
42-
console.log('resize');
43-
setEditorHeight(0);
44-
}}
45-
my={2}>
106+
my={2}
107+
>
46108
<MonacoEditor
47-
48109
height={editorHeight}
49110
language={language}
50111
theme={monacoTheme}
@@ -55,16 +116,15 @@ const ChakraMarkdown = React.memo<any>(({ content }) => {
55116
scrollBeyondLastLine: false,
56117
lineNumbers: "off",
57118
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',
63124
cursorWidth: 1,
64125
wordWrap: 'on',
65126
}}
66-
onMount={(editor, monaco) => {
67-
console.log('mount');
127+
onMount={(editor) => {
68128
const keepIds = ["editor.action.clipboardCopyAction"];
69129
const contextmenu = editor.getContribution('editor.contrib.contextmenu');
70130
const realMethod = contextmenu._getMenuActions;
@@ -75,65 +135,35 @@ const ChakraMarkdown = React.memo<any>(({ content }) => {
75135
});
76136
};
77137

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();
130159
});
131160
}}
132161
/>
133162
</Box>
134163
);
135164
},
136165
};
166+
137167
return <ReactMarkdown components={renderers} children={content} />;
138168
});
139169

0 commit comments

Comments
 (0)