11// Pure: terminal size + zone visibility + overlay mode → rects. No I/O.
22
3- import { resolveContentWidth , resolveSideMargin } from "./zones.js" ;
3+ import {
4+ Align ,
5+ Direction ,
6+ Display ,
7+ Edge ,
8+ FlexDirection ,
9+ Justify ,
10+ Node ,
11+ PositionType ,
12+ } from "@opentui/core/yoga" ;
413import {
514 COLLAPSE_ORDER ,
615 FLEET_BOARD_CAP_FRACTION ,
@@ -13,6 +22,8 @@ import {
1322 PROMPT_CAP_FRACTION ,
1423 PROMPT_IDLE_ROWS ,
1524 ZONE_REGISTRY ,
25+ resolveContentWidth ,
26+ resolveSideMargin ,
1627 type ZoneId ,
1728} from "./zones.js" ;
1829
@@ -300,26 +311,80 @@ function collapseOnce(
300311 return null ;
301312}
302313
303- function assignRects (
314+ function roundLayout ( n : number ) : number {
315+ return Math . round ( n ) ;
316+ }
317+
318+ /**
319+ * Place already-collapsed zone heights with Yoga. The ordered collapse pass
320+ * stays in TypeScript: unequal `flexShrink` weights (the usual priority
321+ * trick) make this Yoga build stop shrinking and overflow the column, and
322+ * equal weights shrink zones together instead of in `COLLAPSE_ORDER`.
323+ * Gutters are root padding; each zone is a column item with its height
324+ * locked (basis, min, and max) so the native layout is the rect source.
325+ */
326+ function layoutRects (
304327 heights : MutableHeights ,
305328 terminal : TerminalSize ,
306329) : Partial < Record < ZoneId , Rect > > {
307- const regions : Partial < Record < ZoneId , Rect > > = { } ;
308- const x = resolveSideMargin ( terminal . columns ) ;
309- const contentWidth = resolveContentWidth ( terminal . columns ) ;
310- let y = 0 ;
311- for ( const id of PAINT_ORDER ) {
312- const height = heights [ id ] ;
313- if ( height <= 0 ) continue ;
314- regions [ id ] = {
315- x,
316- y,
317- width : contentWidth ,
318- height,
319- } ;
320- y += height ;
330+ const sideMargin = resolveSideMargin ( terminal . columns ) ;
331+ const root = Node . create ( ) ;
332+ try {
333+ root . setWidth ( terminal . columns ) ;
334+ root . setHeight ( terminal . rows ) ;
335+ root . setFlexDirection ( FlexDirection . Column ) ;
336+ root . setJustifyContent ( Justify . FlexStart ) ;
337+ root . setAlignItems ( Align . Stretch ) ;
338+ root . setDisplay ( Display . Flex ) ;
339+ root . setPositionType ( PositionType . Relative ) ;
340+ root . setPadding ( Edge . Left , sideMargin ) ;
341+ root . setPadding ( Edge . Right , sideMargin ) ;
342+ root . setPadding ( Edge . Top , 0 ) ;
343+ root . setPadding ( Edge . Bottom , 0 ) ;
344+
345+ const placed : ZoneId [ ] = [ ] ;
346+ for ( const id of PAINT_ORDER ) {
347+ const height = heights [ id ] ;
348+ if ( height <= 0 ) continue ;
349+ const child = Node . create ( ) ;
350+ child . setDisplay ( Display . Flex ) ;
351+ child . setPositionType ( PositionType . Relative ) ;
352+ child . setFlexDirection ( FlexDirection . Column ) ;
353+ child . setFlexGrow ( 0 ) ;
354+ child . setFlexShrink ( 0 ) ;
355+ child . setFlexBasis ( height ) ;
356+ child . setHeight ( height ) ;
357+ child . setMinHeight ( height ) ;
358+ child . setMaxHeight ( height ) ;
359+ child . setWidthPercent ( 100 ) ;
360+ child . setMargin ( Edge . Left , 0 ) ;
361+ child . setMargin ( Edge . Right , 0 ) ;
362+ child . setMargin ( Edge . Top , 0 ) ;
363+ child . setMargin ( Edge . Bottom , 0 ) ;
364+ root . insertChild ( child , root . getChildCount ( ) ) ;
365+ placed . push ( id ) ;
366+ }
367+
368+ root . calculateLayout ( terminal . columns , terminal . rows , Direction . LTR ) ;
369+
370+ const regions : Partial < Record < ZoneId , Rect > > = { } ;
371+ for ( let index = 0 ; index < placed . length ; index += 1 ) {
372+ const id = placed [ index ] ;
373+ if ( id === undefined ) continue ;
374+ const child = root . getChild ( index ) ;
375+ if ( child === null ) continue ;
376+ const layout = child . getComputedLayout ( ) ;
377+ regions [ id ] = {
378+ x : roundLayout ( layout . left ) ,
379+ y : roundLayout ( layout . top ) ,
380+ width : roundLayout ( layout . width ) ,
381+ height : roundLayout ( layout . height ) ,
382+ } ;
383+ }
384+ return regions ;
385+ } finally {
386+ root . freeRecursive ( ) ;
321387 }
322- return regions ;
323388}
324389
325390/** Resolve shell region rects from terminal size, optional chrome, and
@@ -426,7 +491,7 @@ export function resolveGeometry(input: GeometryInput): GeometryLayout {
426491 heights . transcript += terminal . rows - assigned ;
427492 }
428493
429- const regions = assignRects ( heights , terminal ) ;
494+ const regions = layoutRects ( heights , terminal ) ;
430495
431496 return {
432497 terminal,
0 commit comments