What's wrong
UIApplication.SyncRootToConsole (TUI/Services/UIApplication.cs:~272-290) runs ArrangeTree only when the root has no dimensions yet or the console was resized. Invalidate() (UIElementBase.cs:321-326) raises Invalidated but never causes a re-arrange. So any change to the tree after the first frame keeps the stale layout.
Reproduction (ran, using RecordingConsoleProvider)
- A: showing a hidden element
- The root is
StackPanel { a, b }, where b.IsVisible = false.
- Call
app.Render(), then set b.IsVisible = true, then call app.Render().
- Actual:
b's text is never drawn, because b still has its default position and empty dimensions.
- Expected:
b is drawn on row 1.
- B: a host-assigned root size
var root = new StackPanel { new TextElement("abc") }; root.Dimensions = new(20, 5);
- Call
app.Render().
- Actual: nothing is drawn, because the root has a size so the arrange step is skipped and the child has no dimensions.
- Expected:
abc is drawn.
- Other cases: the same applies to any
Text or size change that should move its siblings.
Why it matters
Dynamic UIs, where elements appear or disappear or text length changes, render with stale geometry until the user happens to resize the terminal.
Suggested fix / acceptance criteria
- Re-arrange the tree on every
Render(). Each pass already clears and redraws the whole screen (CLAUDE.md, step 3), so an arrange pass is cheap in comparison.
- Alternatively, track a layout-dirty flag that
Invalidate / IsVisible / Text changes set, and arrange when it is set.
- Add tests for both repro cases.
What's wrong
UIApplication.SyncRootToConsole(TUI/Services/UIApplication.cs:~272-290) runsArrangeTreeonly when the root has no dimensions yet or the console was resized.Invalidate()(UIElementBase.cs:321-326) raisesInvalidatedbut never causes a re-arrange. So any change to the tree after the first frame keeps the stale layout.Reproduction (ran, using
RecordingConsoleProvider)StackPanel { a, b }, whereb.IsVisible = false.app.Render(), then setb.IsVisible = true, then callapp.Render().b's text is never drawn, becausebstill has its default position and empty dimensions.bis drawn on row 1.var root = new StackPanel { new TextElement("abc") }; root.Dimensions = new(20, 5);app.Render().abcis drawn.Textor size change that should move its siblings.Why it matters
Dynamic UIs, where elements appear or disappear or text length changes, render with stale geometry until the user happens to resize the terminal.
Suggested fix / acceptance criteria
Render(). Each pass already clears and redraws the whole screen (CLAUDE.md, step 3), so an arrange pass is cheap in comparison.Invalidate/IsVisible/Textchanges set, and arrange when it is set.