@@ -29,6 +29,7 @@ import { Icon } from "../Icon";
2929export const CodeEmbed = ( props ) => {
3030 const { ref : liveRegionRef , announce } = useLiveRegion ( ) ;
3131 const [ rendered , setRendered ] = useState ( false ) ;
32+
3233 const initialCode = props . initialValue ?? "" ;
3334 // Source code from Google Docs sometimes uses a unicode non-breaking space
3435 // instead of a normal one, but these break the code frame, so we replace them here.
@@ -54,6 +55,9 @@ export const CodeEmbed = (props) => {
5455 }
5556
5657 const codeFrameRef = useRef ( null ) ;
58+ const editorRef = useRef ( null ) ;
59+ const isScrollable = props . scrollable ?? false ;
60+ const [ hasScrollbar , setHasScrollbar ] = useState ( false ) ;
5761
5862 const updateOrReRun = ( ) => {
5963 if ( codeString === previewCodeString ) {
@@ -79,6 +83,18 @@ export const CodeEmbed = (props) => {
7983 }
8084 } , [ ] ) ;
8185
86+ // only observe scroll when scrollable
87+ useEffect ( ( ) => {
88+ if ( ! rendered || ! isScrollable ) return ;
89+ const scroller = editorRef . current ?. querySelector ( ".cm-scroller" ) ;
90+ if ( ! scroller ) return ;
91+ const observer = new ResizeObserver ( ( ) => {
92+ setHasScrollbar ( scroller . scrollHeight > scroller . clientHeight ) ;
93+ } ) ;
94+ observer . observe ( scroller ) ;
95+ return ( ) => observer . disconnect ( ) ;
96+ } , [ rendered , isScrollable ] ) ;
97+
8298 if ( ! rendered ) return < div className = "code-placeholder" /> ;
8399
84100 return (
@@ -92,6 +108,8 @@ export const CodeEmbed = (props) => {
92108 < div >
93109 < CodeFrame
94110 jsCode = { previewCodeString }
111+ cssCode = { props . cssCode }
112+ htmlBodyCode = { props . htmlBodyCode }
95113 width = { previewWidth }
96114 height = { previewHeight }
97115 base = { props . base }
@@ -125,11 +143,12 @@ export const CodeEmbed = (props) => {
125143 </ div >
126144 </ div >
127145 ) : null }
128- < div className = "code-editor-container relative w-full" >
146+ < div ref = { editorRef } className = "code-editor-container relative w-full" >
129147 < CodeMirror
130148 value = { codeString }
131149 theme = "light"
132150 width = "100%"
151+ height = { isScrollable ? "300px" : undefined }
133152 minimalSetup = { {
134153 highlightSpecialChars : false ,
135154 history : false ,
@@ -139,19 +158,27 @@ export const CodeEmbed = (props) => {
139158 historyKeymap : true ,
140159 } }
141160 basicSetup = { {
142- lineNumbers : false ,
143- foldGutter : false ,
161+ lineNumbers : hasScrollbar ,
162+ foldGutter : isScrollable ,
144163 autocompletion : false ,
145164 } }
146165 indentWithTab = { false }
147- extensions = { [ javascript ( ) , EditorView . lineWrapping ] }
166+ extensions = { [ javascript ( ) , EditorView . lineWrapping , EditorView . theme ( {
167+ ".cm-scroller" : {
168+ overflowY : isScrollable ? "auto" : "visible" ,
169+ } ,
170+ } ) ] }
148171 onChange = { ( val ) => setCodeString ( val ) }
149172 editable = { props . editable }
150173 onCreateEditor = { ( editorView ) =>
151174 ( editorView . contentDOM . ariaLabel = "Code Editor" )
152175 }
153176 />
154- < div className = "absolute right-0 top-0 flex flex-col gap-xs p-xs md:flex-row" >
177+ < div
178+ className = { `absolute top-0 flex flex-col gap-xs p-xs md:flex-row ${
179+ isScrollable && hasScrollbar ? "right-[25px]" : "right-0"
180+ } `}
181+ >
155182 < CopyCodeButton textToCopy = { codeString || initialCode } />
156183 < CircleButton
157184 onClick = { ( ) => {
0 commit comments