@@ -3,6 +3,7 @@ import { clampNonNegative, clampWithin } from "../engine/bounds.js";
33import { isVNode } from "../engine/guards.js" ;
44import { ok } from "../engine/result.js" ;
55import type { LayoutTree } from "../engine/types.js" ;
6+ import { measureTextCells } from "../textMeasure.js" ;
67import type { Axis , Rect , Size } from "../types.js" ;
78import type { LayoutResult } from "../validateProps.js" ;
89
@@ -203,37 +204,70 @@ export function layoutOverlays(
203204
204205 const title = typeof props . title === "string" ? props . title : undefined ;
205206
207+ const content = isVNode ( props . content ) ? props . content : null ;
208+ const actionsRaw = Array . isArray ( props . actions ) ? props . actions : [ ] ;
209+ const actions : VNode [ ] = [ ] ;
210+ for ( const a of actionsRaw ) {
211+ if ( isVNode ( a ) ) actions . push ( a ) ;
212+ }
213+
214+ const border = 1 ;
215+ const titleH = title ? 1 : 0 ;
216+ const actionsH = actions . length > 0 ? 1 : 0 ;
217+
206218 const maxWidth =
207219 typeof props . maxWidth === "number" && props . maxWidth > 0
208220 ? Math . floor ( props . maxWidth )
209221 : rectW ;
210222
211- let modalW =
212- typeof props . width === "number" && props . width > 0
213- ? Math . floor ( props . width )
214- : Math . floor ( rectW * 0.7 ) ;
215-
216- modalW = clampNonNegative ( Math . min ( modalW , maxWidth ) ) ;
217- modalW = clampWithin ( modalW , Math . min ( 10 , rectW ) , rectW ) ;
218- if ( rectW >= 4 ) modalW = Math . min ( modalW , rectW - 2 ) ;
219-
220223 let modalH = Math . floor ( rectH * 0.6 ) ;
221224 modalH = clampWithin ( modalH , Math . min ( 5 , rectH ) , rectH ) ;
222225 if ( rectH >= 4 ) modalH = Math . min ( modalH , rectH - 2 ) ;
223226
224- const mx = x + Math . floor ( ( rectW - modalW ) / 2 ) ;
225- const my = y + Math . floor ( ( rectH - modalH ) / 2 ) ;
227+ const maxModalW = clampNonNegative ( Math . min ( rectW , maxWidth ) ) ;
228+ const maxInnerW = clampNonNegative ( maxModalW - border * 2 ) ;
229+ const maxInnerH = clampNonNegative ( modalH - border * 2 - titleH - actionsH ) ;
226230
227- const content = isVNode ( props . content ) ? props . content : null ;
228- const actionsRaw = Array . isArray ( props . actions ) ? props . actions : [ ] ;
229- const actions : VNode [ ] = [ ] ;
230- for ( const a of actionsRaw ) {
231- if ( isVNode ( a ) ) actions . push ( a ) ;
231+ let modalW : number ;
232+ if ( typeof props . width === "number" && props . width > 0 ) {
233+ modalW = Math . floor ( props . width ) ;
234+ } else if ( props . width === "auto" ) {
235+ let contentW = 0 ;
236+ if ( content ) {
237+ const sizeRes = measureNode ( content , maxInnerW , maxInnerH , "column" ) ;
238+ if ( ! sizeRes . ok ) return sizeRes ;
239+ contentW = clampNonNegative ( Math . min ( maxInnerW , sizeRes . value . w ) ) ;
240+ }
241+
242+ let actionsW = 0 ;
243+ if ( actions . length > 0 ) {
244+ const gap = 1 ;
245+ let total = 0 ;
246+ for ( let i = 0 ; i < actions . length ; i ++ ) {
247+ const a = actions [ i ] ;
248+ if ( ! a ) continue ;
249+ const sizeRes = measureNode ( a , maxInnerW , 1 , "row" ) ;
250+ if ( ! sizeRes . ok ) return sizeRes ;
251+ const aw = clampNonNegative ( Math . min ( maxInnerW , sizeRes . value . w ) ) ;
252+ total += aw ;
253+ if ( i < actions . length - 1 ) total += gap ;
254+ }
255+ actionsW = total ;
256+ }
257+
258+ const innerW = Math . max ( contentW , actionsW ) ;
259+ const titleW = title ? measureTextCells ( title ) + 4 : 0 ;
260+ modalW = Math . max ( innerW + border * 2 , titleW ) ;
261+ } else {
262+ modalW = Math . floor ( rectW * 0.7 ) ;
232263 }
233264
234- const border = 1 ;
235- const titleH = title ? 1 : 0 ;
236- const actionsH = actions . length > 0 ? 1 : 0 ;
265+ modalW = clampNonNegative ( Math . min ( modalW , maxWidth ) ) ;
266+ modalW = clampWithin ( modalW , Math . min ( 10 , rectW ) , rectW ) ;
267+ if ( rectW >= 4 ) modalW = Math . min ( modalW , rectW - 2 ) ;
268+
269+ const mx = x + Math . floor ( ( rectW - modalW ) / 2 ) ;
270+ const my = y + Math . floor ( ( rectH - modalH ) / 2 ) ;
237271
238272 const innerX = mx + border ;
239273 const innerY = my + border + titleH ;
0 commit comments