A custom action declaration, mirroring the official custom-action
shape: name, description, params in positional order. Declaring an
action makes the evaluator validate @Name(...) calls against
these params; an invalid call evaluates to null with a
runtime-error instead of passing through unchecked. Undeclared
action names still pass through as before, for hosts that dispatch
actions they do not want to declare.
The colours a chart paints with, bridged from
OpenUIColorScheme by the renderer (axisText from textMuted,
grid from grid, border from border). Defaults reproduce the
previously hardcoded greys, so a widget built directly — no
renderer, no theme — looks exactly as before. _axisStyle
stays the measuring style (metrics don't depend on colour);
painters use _axisLabelStyle for the actual labels.
Legend used by the cartesian/radar/scatter widgets: a swatch
Container per series (the colour test in controller_theme_test
pins this exact shape) plus the series label. With onToggle
the rows become tappable (React parity: clicking a legend entry
hides its series) and hidden rows dim to 0.3. Like React's
DefaultLegend, items that don't fit the width collapse behind
a "N more" / "Show Less" toggle; when everything fits, the tree
is the old one, so the colour test still holds.
A citation chip: [n]. Tapping calls onTap when supplied and
otherwise does nothing. title is shown as a tooltip; url is
carried for hosts that resolve the citation on tap.
Range-mode date picker: the value is a {from, to} map of
yyyy-MM-dd strings, mirroring React's DateRange {from, to} shape.
Displays "from → to", either side alone, or "Not selected" when empty.
A custom function, mirroring the official defineFunction shape:
name, description, params in positional order, optional returns type,
and a pure synchronous implementation that receives one object keyed
by the param names, with defaults applied. An optional param with no
default is left out of the object.
An incremental OpenUI Lang parser: the same result as parseOpenUI
for the same text, but repeated parses of a growing text only redo
the work that changed.
Cumulative counters for an IncrementalOpenUIParser: how many
parses ran, how many lines were actually tokenized and parsed, and
how many statements were freshly evaluated (memo misses). On a
long stream these stay near the number of lines/statements, while
a full re-parse per push would multiply them by the push count.
The semantic colours a component needs. The first three are the
core (accent, background, text on that background); the rest
default to the previously hardcoded values, so a scheme built
with only the core three looks exactly as before:
Owns everything a renderer needs beyond the widget tree: form state,
Query data and failure state, action dispatch, and the streaming
buffer. The renderer in controller mode is a thin view over this
object: it rebuilds when the controller notifies, and every form
change or action goes back through here, so hosts can drive the
same UI from outside the widget tree (and read formState after
any interaction).
Visual theme for the renderer. Hosts pass one to OpenUIController;
the renderer reads it from the controller in controller mode and
otherwise uses OpenUIThemeData.light. Builders are injection
points: when supplied, the renderer uses them instead of its
built-in skeleton / error views.
A Query whose tool call failed. It is a QueryLoading so it
propagates through field access, operators and functions exactly
like a still-loading value, but it carries the tool name so the
component that directly depends on it can render as a Query-error
node (__QueryError) instead of a skeleton.
Sentinel for a Query whose data has not arrived yet and which has no
initial value. It propagates through field access, index access,
operators and built-in functions, and makes the component that
directly depends on it render as a skeleton (see __Skeleton).
A Query statement the renderer should run through the host's tool
provider: name = Query("tool", {params}, initial?).
initial is the value to render while loading, when given.
Facade over the renderer state handed to built-in builders. The
state class implements it by delegating to its private members;
a builder can be unit-tested against a fake of this interface
without a renderer.
Hand primitives (the "hand" layer of the OpenUI React SDK): skeleton
placeholders, citations and sources. These are plain widgets a host
can also use directly, outside the renderer.
A list of sources: one row per item, with a favicon image when
SourceItem.faviconUrl is present and the title text. Tapping a
row currently does nothing: the brief's theme link handler does
not exist in OpenUIThemeData (Task 2), and no host use in this
task requires one, so adding it here would be scope expansion.
A link handler (theme-level or per-widget) is deferred to a later
task that actually needs it.
Incremental streaming: two IncrementalOpenUIParser instances,
one for the complete lines (stable) and one for the display text
(complete lines plus the autoclosed pending line). Previously each
push ran two full parses of the whole response; now each push only
parses new lines and re-evaluates changed statements.
Autocloser: make partial (mid-stream) text syntactically valid by
appending the minimal closing quote and brackets. Brackets inside
strings do not count, a trailing comma is dropped, and a trailing
backslash inside an unfinished string is dropped before closing it.
Pure data step of the scatter chart, kept separate from the
painter so tests can pin the bubble radii without a widget.
A point's z scales its bubble (area proportional to z, as in a
bubble chart); points without z keep the default radius.
Axis tick labels, React's numberTickFormatter: K/M/B/T
abbreviation at 1e3/1e6/1e9/1e12 (1 decimal below 10 units,
none at 10 and above), plain integers below 1000, and 2
decimals for non-integers below 1000. This is the axis
formatter only — tooltips keep their own formatter
(_fmtTooltipNum), which groups below 100000 instead.
Icon name to Material icon. React names are lucide kebab-case
(e.g. 'circle-check'); they are normalized to snake_case for the
lookup. When a name does not resolve, React falls back to the
category's representative icon (categoryFallbacks), then to a
generic dot; this port maps those fallbacks to Material icons
instead of failing the whole component.
d3-style nice domain: dataMin, dataMax widened to round tick
boundaries. throughZero pins the domain to include zero (the
React cartesian rule); scatter axes pass false. pixelsPerTick
sets the target tick density (40 for value axes, 60 for the
wider bottom labels).
Stacked bounds: per category, positives stack up and negatives
stack down (React's sign offset), so the domain covers the
largest positive stack and the deepest negative stack.
Validates value against a React-style rules object ({required?,
email?, url?, numeric?, min?, max?, minLength?, maxLength?,
pattern?}). Returns the first failure message, or null when the
value passes. Empty values (null, '', empty list/map) skip all
checks except required, so optional untouched fields never fail.
For list values, min/max/numeric apply to the first element and
minLength/maxLength to the length. Used by FormControl for live
errors; hosts can call it directly for submit-time validation —
there is no built-in submit gate.
Builds one built-in component. ctx is the renderer's facade: it
exposes exactly what a built-in builder may touch (theme, form
state, dispatch, child rendering, shared layout helpers), so a
builder never reaches into the renderer's private fields directly.
Custom registry builders keep their own, narrower signature.
Full geometry for a vertical cartesian chart, in content
coordinates (the plot painter) plus the fixed axis width.
labelAngle is 0 for horizontal labels, -pi/4 for condensed
angled labels; labelInterval thins condensed labels (1 =
every label); labelWidth is the box a condensed label wraps
or truncates to (in scroll mode it is just the slot width).
Builds a component node. renderChild renders a child node through the
renderer's own node builder, so theme, form state and Query data flow
through a custom component exactly as they do through a built-in one.
Plot geometry for a scatter chart, shared by the painter and
the tooltip hit test. Both axes are numeric (React's scatter
axes): nice domains without zero anchoring, Y on the left with
horizontal gridlines, X at the bottom with vertical gridlines.