@@ -115,7 +115,30 @@ qx.Class.define("osparc.ui.markdown.Markdown2", {
115115 const safeHtml = osparc . wrapper . DOMPurify . getInstance ( ) . sanitize ( html ) ;
116116
117117 // flow-root prevents margin collapsing; inline style avoids extra stylesheet juggling
118- this . setHtml ( `<div class="${ this . self ( ) . WRAP_CLASS } " style="display:flow-root;">${ safeHtml } </div>` ) ;
118+ let mdRoot ;
119+ const max = 220 ;
120+ if ( max ) {
121+ mdRoot = `
122+ <div class="${ this . self ( ) . WRAP_CLASS } " style="display:flow-root;">
123+ <div class="osparc-md-measure"
124+ style="
125+ display:inline-block;
126+ width:max-content;
127+ max-width:${ max } px;
128+ white-space:normal;
129+ overflow-wrap:anywhere; /* break long tokens */
130+ ">
131+ ${ safeHtml }
132+ </div>
133+ </div>
134+ ` ;
135+ } else {
136+ mdRoot = `
137+ <div class="${ this . self ( ) . WRAP_CLASS } " style="display:flow-root;">
138+ ${ safeHtml }
139+ </div>` ;
140+ }
141+ this . setHtml ( mdRoot ) ;
119142
120143 // resize once DOM is updated/painted
121144 this . __scheduleResize ( ) ;
@@ -160,20 +183,25 @@ qx.Class.define("osparc.ui.markdown.Markdown2", {
160183 void domElement . offsetHeight ;
161184
162185 // measure the wrapper we injected (covers ALL children)
163- const inner = domElement . querySelector ( "." + this . self ( ) . WRAP_CLASS ) || domElement ;
164- const rect = inner . getBoundingClientRect ( ) ;
165- const contentH = Math . ceil ( rect ? rect . height : 0 ) ;
166- const contentW = Math . ceil ( rect ? rect . width : 0 ) ;
186+ const root = domElement . querySelector ( "." + this . self ( ) . WRAP_CLASS ) || domElement ;
187+ const meas = root . querySelector ( ".osparc-md-measure" ) || root ;
188+
189+ const rH = meas . getBoundingClientRect ( ) . height ;
190+ const rW = meas . getBoundingClientRect ( ) . width ;
167191
168192 // include widget insets (decorator/padding/border)
169- const insets = this . getInsets ? this . getInsets ( ) : { top : 0 , bottom : 0 , left : 0 , right : 0 } ;
170- const totalH = Math . max ( 0 , contentH + ( insets . top || 0 ) + ( insets . bottom || 0 ) ) ;
171- const totalW = Math . max ( 0 , contentW + ( insets . left || 0 ) + ( insets . right || 0 ) ) ;
193+ const insets = this . getInsets ? this . getInsets ( ) : { top :0 , right : 0 , bottom : 0 , left : 0 } ;
194+ const totalH = Math . ceil ( ( rH || 0 ) + ( insets . top || 0 ) + ( insets . bottom || 0 ) ) ;
195+ const totalW = Math . ceil ( ( rW || 0 ) + ( insets . left || 0 ) + ( insets . right || 0 ) ) ;
172196
173197 this . setMinHeight ( totalH ) ;
174198 this . setHeight ( totalH ) ;
175- this . setMinWidth ( totalW ) ;
176- this . setWidth ( totalW ) ;
199+
200+ // width: shrink-to-fit, but cap at a max
201+ this . setAllowGrowX ( false ) ; // prevent parent layout from stretching it
202+ this . setMaxWidth ( null ) ; // measurer already capped; we set exact width
203+ this . setMinWidth ( 1 ) ; // avoid 0 when empty
204+ this . setWidth ( totalW ) ; // exact bubble width
177205
178206 console . log ( "totalH" , totalH , "totalW" , totalW ) ;
179207 } ) ;
0 commit comments