Summary
The composer text field grows sideways. Long input (no newlines) expands the textEntry in the horizontal chrome box and pushes ▶ Send / ■ Stop off the canvas before the field wraps and grows up.
#702 / #709 fixed caret h-scroll (scroll_horizontal = false so break_lines can fire). This is a different miss: the widget min-size width still tracks the unwrapped line, so the parent row gives the field the long line and the icons get leftover 0.
docs/harness-limits.md Wrap / grow: wrap at field width, grow vertically to COMPOSER_MAX_CHROME_H (124 px), then scroll inside. Icons stay on-canvas (TOUCH_H squares, gravity_y = 1.0). Never a horizontal gutter. Repo no-h-scroll (#344 / #457 / #579).
Observed
- Focus the canvas composer (
Message the model…).
- Type or paste a long single line — longer than the field, no Enter.
- Watch the ▶ (and Busy ■) on the same row.
Actual: the input box widens. The trailing icon(s) slide off the right edge / get crushed before the chrome grows up. Hard to send; Busy Stop can leave the viewport.
Expected: field width is the leftover of the chrome row after the icon pack. Long text wraps at that width. Chrome grows up (idle ~44 px → cap 124 px). Past the cap, the entry scrolls vertically inside. ▶/■ stay fully on-canvas at TOUCH_H for every frame of that growth.
Likely seam
Horizontal composer box (native/harness/src/ui.zig ~595): textEntry (expand = .horizontal, min_size_content.w = 120, max_size_content.w = max_float_safe) then fixed TOUCH_H icon buttons.
| Piece |
Role |
dvui.box .dir = .horizontal |
Field + icons share one row |
textEntry scroll_horizontal = false |
Inner scroll .none → wrap at current viewport.w (#709) |
max_size_content.w = max_float_safe |
TextEntryWidget.init strips it; not a width cap vs the icons |
min_size_content.w = 120 |
Floor only. If deinit reports unwrapped line width as min-size.w, the box allocates that first |
Icon min_size_content TOUCH_H×TOUCH_H |
No gravity_x / reserved trailing slot; leftover after the field |
scroll_horizontal = false can wrap glyphs inside a field that has already stolen the icon columns.
Goal
- Composer field never grows past
chrome.w − icon_pack.w − margin.
- Icons stay on-canvas (idle one ▶; Busy ▶ + ■).
- Long lines wrap, then grow up, then scroll inside. No horizontal gutter.
Non-goals
Related
native/harness/src/ui.zig — composer chrome box + textEntry InitOptions + icon buttons
docs/harness-limits.md — Wrap / grow, Icon button
- Closed wrap of caret pan: #702 / #709
Suggested next: type a long line with no spaces; the ▶ must stay fully visible while the field wraps and the chrome grows up.
Summary
The composer text field grows sideways. Long input (no newlines) expands the
textEntryin the horizontal chrome box and pushes ▶ Send / ■ Stop off the canvas before the field wraps and grows up.#702 / #709 fixed caret h-scroll (
scroll_horizontal = falsesobreak_linescan fire). This is a different miss: the widget min-size width still tracks the unwrapped line, so the parent row gives the field the long line and the icons get leftover 0.docs/harness-limits.mdWrap / grow: wrap at field width, grow vertically toCOMPOSER_MAX_CHROME_H(124 px), then scroll inside. Icons stay on-canvas (TOUCH_Hsquares,gravity_y = 1.0). Never a horizontal gutter. Repo no-h-scroll (#344 / #457 / #579).Observed
Message the model…).Actual: the input box widens. The trailing icon(s) slide off the right edge / get crushed before the chrome grows up. Hard to send; Busy Stop can leave the viewport.
Expected: field width is the leftover of the chrome row after the icon pack. Long text wraps at that width. Chrome grows up (idle ~44 px → cap 124 px). Past the cap, the entry scrolls vertically inside. ▶/■ stay fully on-canvas at
TOUCH_Hfor every frame of that growth.Likely seam
Horizontal composer box (
native/harness/src/ui.zig~595):textEntry(expand = .horizontal,min_size_content.w = 120,max_size_content.w = max_float_safe) then fixedTOUCH_Hicon buttons.dvui.box.dir = .horizontaltextEntryscroll_horizontal = false.none→ wrap at current viewport.w (#709)max_size_content.w = max_float_safeTextEntryWidget.initstrips it; not a width cap vs the iconsmin_size_content.w = 120min_size_contentTOUCH_H×TOUCH_Hgravity_x/ reserved trailing slot; leftover after the fieldscroll_horizontal = falsecan wrap glyphs inside a field that has already stolen the icon columns.Goal
chrome.w − icon_pack.w − margin.Non-goals
scroll_horizontal = false(that was the harness: composer text field horizontally scrolls instead of wrapping and growing #702 caret pan).COMPOSER_MAX_CHROME_H/TOUCH_H.multiline = false).Related
native/harness/src/ui.zig— composer chrome box + textEntry InitOptions + icon buttonsdocs/harness-limits.md— Wrap / grow, Icon buttonSuggested next: type a long line with no spaces; the ▶ must stay fully visible while the field wraps and the chrome grows up.