Phosphor::MockWidget
Abstract base for reusable, app-agnostic UI primitives.
A MockWidget owns its internal render state (WidgetState) and responds
to generic Cmd values via handle_cmd. It knows nothing about the
application's Msg enum, AppState, or theme — those concerns live in
the Widget wrapper.
This layer is extractable as a published shard: ListMock, SpinnerMock,
and similar primitives have no dependency on any specific application.
Subclasses must define:
- A
Propsrecord carrying only already-resolvedStylevalues. property props : Propstyped to the subclass's ownPropsrecord.render_content(frame, buf)writing cells viabuf.set_string.handle_cmd(cmd)mutatingstateand returning aCmdResult.
Constructors
Initialises the widget with an optional state.
state defaults to a freshly-zeroed WidgetState; pass a subclass
instance to restore cursor or scroll position across mounts.
Instance methods
How often this widget needs a TickEvent to animate — a spinner's
frame advance, an indeterminate progress bar's moving block, a
notification's self-dismiss countdown. nil (the default) means it
never animates on its own.
View#animation_interval takes the minimum non-nil value across
every mounted widget; App#run's main loop uses that to decide how
long it can block on event_ch.receive before it needs to wake up
and synthesize a tick itself — see App#run's doc comment. This
replaces manually mounting a TickPort in Screen#on_mount for
widgets that declare their own interval here.
Override to return a value from the subclass's own Props (e.g.
props.animation_interval, if that Props record declares one).
Responds to cmd, mutating state if appropriate.
Returns CmdResult::Rerender when the widget's visual state changed and
a repaint is needed, CmdResult::Bubble to forward an unhandled command
to the parent, or CmdResult::None when no repaint is required.
Returns true if (x, y) falls within the bounds of the Frame
this widget was last rendered into. Always false before the first
render call. Used by View#dispatch to route mouse events to the
widget under the cursor.
This widget's preferred row count when rendered at the given width,
or nil (the default) if it has no natural height — e.g. a widget
that always fills whatever frame it's given, rather than wrapping a
fixed amount of content.
View#preferred_height sums this across every mounted widget so
Terminal#auto_resize can size an Inline session's block to fit its
content — see App.run(mode: RenderMode::Inline, height: Terminal::AUTO_HEIGHT). width matters because some widgets wrap
(ParagraphMock) or truncate content depending on how much horizontal
space they get.
Writes this widget's cells into buf within the bounds of frame.
Records frame for hit_test, then delegates to render_content,
which subclasses implement. Not overridden by subclasses.
Writes this widget's cells into buf within the bounds of frame.
Implementations must stay inside frame.x..frame.x + frame.width - 1
and frame.y..frame.y + frame.height - 1. All output goes through
buf.set_string using Style values from props — never hardcoded
ANSI escape sequences.