11// ============================================================================
22// Code Modal - Chatbot Modal with Code Editor
33// ============================================================================
4+
45import type { FunctionComponent , MouseEvent } from 'react' ;
5- import { useState } from 'react' ;
6+ import { useState , useEffect , useRef } from 'react' ;
67import path from 'path-browserify' ;
8+ import type monaco from 'monaco-editor' ;
79
810// Import PatternFly components
911import { CodeEditor } from '@patternfly/react-code-editor' ;
10- import { Button , ModalBody , ModalFooter , ModalHeader , Stack , StackItem } from '@patternfly/react-core' ;
12+ import {
13+ Button ,
14+ getResizeObserver ,
15+ ModalBody ,
16+ ModalFooter ,
17+ ModalHeader ,
18+ Stack ,
19+ StackItem
20+ } from '@patternfly/react-core' ;
1121import FileDetails , { extensionToLanguage } from '../FileDetails' ;
1222import { ChatbotDisplayMode } from '../Chatbot' ;
1323import ChatbotModal from '../ChatbotModal/ChatbotModal' ;
@@ -73,6 +83,34 @@ export const CodeModal: FunctionComponent<CodeModalProps> = ({
7383 ...props
7484} : CodeModalProps ) => {
7585 const [ newCode , setNewCode ] = useState ( code ) ;
86+ const [ editorInstance , setEditorInstance ] = useState < monaco . editor . IStandaloneCodeEditor | null > ( null ) ;
87+ const [ isEditorReady , setIsEditorReady ] = useState ( false ) ;
88+ const containerRef = useRef < HTMLDivElement > ( null ) ;
89+
90+ useEffect ( ( ) => {
91+ if ( ! isModalOpen || ! isEditorReady || ! editorInstance || ! containerRef . current ) {
92+ return ;
93+ }
94+
95+ const handleResize = ( ) => {
96+ if ( editorInstance && isEditorReady && isModalOpen ) {
97+ try {
98+ window . requestAnimationFrame ( ( ) => {
99+ editorInstance . layout ( ) ;
100+ } ) ;
101+ } catch ( error ) {
102+ // eslint-disable-next-line no-console
103+ console . error ( 'ChatBot code modal layout error:' , error ) ;
104+ }
105+ }
106+ } ;
107+
108+ const observer = getResizeObserver ( containerRef . current , handleResize ) ;
109+
110+ return ( ) => {
111+ observer ( ) ;
112+ } ;
113+ } , [ editorInstance , isEditorReady , isModalOpen ] ) ;
76114
77115 const handlePrimaryAction = ( _event : MouseEvent | MouseEvent | KeyboardEvent ) => {
78116 handleModalToggle ( _event ) ;
@@ -89,9 +127,15 @@ export const CodeModal: FunctionComponent<CodeModalProps> = ({
89127 } ;
90128
91129 const onEditorDidMount = ( editor , monaco ) => {
92- editor . layout ( ) ;
93- editor . focus ( ) ;
130+ setEditorInstance ( editor ) ;
131+
94132 monaco . editor . getModels ( ) [ 0 ] . updateOptions ( { tabSize : 5 } ) ;
133+
134+ if ( containerRef . current ) {
135+ setIsEditorReady ( true ) ;
136+ editor . layout ( ) ;
137+ editor . focus ( ) ;
138+ }
95139 } ;
96140
97141 const onCodeChange = ( value : string ) => {
@@ -117,7 +161,7 @@ export const CodeModal: FunctionComponent<CodeModalProps> = ({
117161 < StackItem className = "pf-chatbot__code-modal-file-details" >
118162 < FileDetails fileName = { fileName } />
119163 </ StackItem >
120- < StackItem className = "pf-chatbot__code-modal-editor" >
164+ < div className = "pf-v6-l-stack__item pf- chatbot__code-modal-editor" ref = { containerRef } >
121165 < CodeEditor
122166 isDarkTheme
123167 isLineNumbersVisible = { isLineNumbersVisible }
@@ -132,11 +176,14 @@ export const CodeModal: FunctionComponent<CodeModalProps> = ({
132176 isFullHeight
133177 options = { {
134178 glyphMargin : false ,
135- folding : false
179+ folding : false ,
180+ // prevents Monaco from handling resizing itself
181+ // was causing ResizeObserver issues
182+ automaticLayout : false
136183 } }
137184 { ...props }
138185 />
139- </ StackItem >
186+ </ div >
140187 </ Stack >
141188 </ ModalBody >
142189 < ModalFooter className = { modalFooterClassName } >
0 commit comments