TextInputRenderer
Single-line text input with horizontal scrolling and a fake cursor. The TUI analog of pi-tui's `Input` component. This renderer is **pure**: it paints whatever `value`/`cursor`/`placeholder` the node's props carry. Owning that state across frames (and dispatching backspace, arrows, letter keys to mutate them) is the caller's job — the `RetainedTuiLoop` root factory, a live component, or whatever builds the `TuiNode` tree each tick. That mirrors every other renderer in this namespace: pure node-in/frame-out, no hidden state, no keyboard handler inside the renderer. The cursor is a visible block cell so it survives retained composition and plain output. A zero-width {@see FocusableInterface::CURSOR_MARKER} remains immediately before it for hardware-cursor/IME positioning. Node props (all optional): - `value` string Current text. Default: ''. - `cursor` int Cursor column (offset into value, in visible cells). Default: strlen(value). - `placeholder` string Shown when value is empty. Default: ''. - `secret` bool Mask each visible cell with `*`. Default: false. - `prompt` string Prefix before the input (e.g. '> ' or '$ '). Default: ''. - `focused` bool Override focus state (otherwise read from context). Default: context.focused().
TextInputRenderer::supports()
public function supports(Milpa\Live\ValueObjects\Tui\TuiNode $node): boolTrue only for `text-input` nodes — dispatch is by declared node type, never by where the node came from.
Parameters
| Name | Type | Description |
|---|---|---|
| $node | Milpa\Live\ValueObjects\Tui\TuiNode |
TextInputRenderer::measureHeight()
public function measureHeight(Milpa\Live\ValueObjects\Tui\TuiNode $node, int $width): intHow many rows this input needs at `$width`. One, unless `multiline` is on — then as many as the value wraps to, capped by `maxLines`. The cap matters: without it, pasting a paragraph would push everything else off the screen, and the field would eat the very conversation it is answering.
Parameters
| Name | Type | Description |
|---|---|---|
| $node | Milpa\Live\ValueObjects\Tui\TuiNode | |
| $width | int |
TextInputRenderer::render()
public function render(Milpa\Live\ValueObjects\Tui\TuiNode $node, Milpa\Live\ValueObjects\Tui\TuiRenderContext $context): Milpa\Live\ValueObjects\Tui\TuiFrameDraws the visible window of the value with the fake caret, scrolling horizontally when the value is wider than the bounds. In `multiline` mode it wraps instead: the field grows downward in its own box, which — sitting under the conversation in a vertical stack — reads as growing UPWARD, because every row it takes is a row the conversation gives up. That is what a textarea does, and the third affordance of a question is «write my own answer», which is the one that least fits in a line.
Parameters
| Name | Type | Description |
|---|---|---|
| $node | Milpa\Live\ValueObjects\Tui\TuiNode | |
| $context | Milpa\Live\ValueObjects\Tui\TuiRenderContext |
TextInputRenderer::hasCaret()
public function hasCaret(string $output): boolWhether the rendered output carries the caret marker, i.e. whether this input is the node holding the caret.
Parameters
| Name | Type | Description |
|---|---|---|
| $output | string |
TextInputRenderer::caretPosition()
public function caretPosition(string $output): ?arrayThe row and column of the caret within the rendered output, or null when the output does not carry the marker.
Parameters
| Name | Type | Description |
|---|---|---|
| $output | string |