A2UIAgent.Builder (A2UIAgent v0.1.1)

Copy Markdown View Source

Builds component trees in Elixir and flattens them into the component lists that A2UI messages carry.

A tree is made of component nodes (component/2, or the functions of A2UIAgent.Builder.Basic). A node placed in a property of another node becomes a component of its own, and the property holds its id:

iex> import A2UIAgent.Builder
iex> import A2UIAgent.Builder.Basic
iex> tree =
...>   card(
...>     id: "account",
...>     child:
...>       column(
...>         children: [
...>           text(text: "Account overview"),
...>           button(child: text(text: "Details"), action: event("details"))
...>         ]
...>       )
...>   )
iex> tree |> flatten() |> Enum.map(&{&1["id"], &1["component"]})
[
  {"account__text_1", "Text"},
  {"account__text_2", "Text"},
  {"account__button_1", "Button"},
  {"account__column_1", "Column"},
  {"account", "Card"}
]

Children come before their parents, so every reference points at a component already in the list.

Ids

The root's id is the :root_id option, else its own :id. The other components are named after the root: a node with an :id gets <root>__<id>, and a node without one gets <root>__<name>_<n>, its component name in lower case and a count per name, skipping ids the author gave. A root without an id, and no :root_id, takes such an id under the prefix root. A list of trees is flattened tree by tree; with a :root_id, the trees' roots are <root_id>_0, <root_id>_1 and so on.

Values

Properties are given as a keyword list or a map. Atom keys are written in lower camel case (validation_regexp: becomes "validationRegexp"); string keys are written as they are. Besides plain JSON values and nodes, a property can hold:

Bindings and function calls are written with the keys of the protocol version (path and call before v1.0, @path and @call from it). nil properties are left out.

Catalogs

With the :catalog option, flatten/2 completes each component with the defaults its catalog schema declares for properties the node does not set, emits children in the order the catalog declares the properties holding them, and checks each component against the catalog (A2UICore.Validation.Payload.validate_component/3), raising A2UICore.Error for one the catalog rejects. This is how the reference SDKs' generated builders behave.

Macros (A2UIAgent.Macro) can be called inside a tree; see A2UIAgent.Macro.call/2.

Summary

Types

Properties: a keyword list or a map.

A component tree, or a list of them.

Functions

Accessibility attributes, such as label: and description:.

An action that calls a client function (see call/3).

A data binding. An absolute path (/user/name) reads from the data model's root; a relative one (name) from the enclosing scope, such as a child_list/2 item.

A call of the catalog function name. args follow the key rules of properties. Options: :return_type, written as returnType, and :catalog_id, the catalog the call runs in when it is not the surface's default, written as catalogId from protocol v1.0 (before it a call always runs in the surface's catalog, and the option is left out).

A check rule: condition (usually a call/3) and the message shown when it fails.

Children generated from the data model list at path: template is emitted once and repeated for each item.

A component node. props may set :id; see the moduledoc for keys and values.

An action that sends the event name to the agent, with an optional context (keys written as given).

Flattens tree into a list of component maps, children first.

The messages that put tree on a surface: a createSurface when :catalog_id is given, an updateComponents with the flattened components, and an updateDataModel for each :data_model entry.

A reference to a component already on the surface, by id.

Types

props()

(since 0.1.0)
@type props() :: keyword() | map()

Properties: a keyword list or a map.

tree()

(since 0.1.0)

A component tree, or a list of them.

Functions

accessibility(attributes)

(since 0.1.0)
@spec accessibility(props()) :: map()

Accessibility attributes, such as label: and description:.

iex> A2UIAgent.Builder.accessibility(label: "Close")
%{"label" => "Close"}

action(call)

(since 0.1.0)
@spec action(A2UIAgent.Builder.FunctionCall.t()) :: map()

An action that calls a client function (see call/3).

bind(path)

(since 0.1.0)

A data binding. An absolute path (/user/name) reads from the data model's root; a relative one (name) from the enclosing scope, such as a child_list/2 item.

call(name, args \\ [], options \\ [])

(since 0.1.0)

A call of the catalog function name. args follow the key rules of properties. Options: :return_type, written as returnType, and :catalog_id, the catalog the call runs in when it is not the surface's default, written as catalogId from protocol v1.0 (before it a call always runs in the surface's catalog, and the option is left out).

iex> import A2UIAgent.Builder.Basic
iex> text(id: "root", text: A2UIAgent.Builder.call("shout", [value: "hi"], catalog_id: "https://example.com/c.json"))
...> |> A2UIAgent.Builder.flatten()
[
  %{
    "id" => "root",
    "component" => "Text",
    "text" => %{"@call" => "shout", "args" => %{"value" => "hi"}, "catalogId" => "https://example.com/c.json"}
  }
]

check(condition, message)

(since 0.1.0)
@spec check(term(), String.t()) :: map()

A check rule: condition (usually a call/3) and the message shown when it fails.

child_list(path, template)

(since 0.1.0)

Children generated from the data model list at path: template is emitted once and repeated for each item.

component(name, props \\ [])

(since 0.1.0)
@spec component(String.t(), props()) :: A2UIAgent.Builder.Component.t()

A component node. props may set :id; see the moduledoc for keys and values.

iex> A2UIAgent.Builder.component("Text", id: "title", text: "Hello").props
[{"text", "Hello"}]

event(name, context \\ nil)

(since 0.1.0)
@spec event(String.t(), props() | nil) :: map()

An action that sends the event name to the agent, with an optional context (keys written as given).

iex> A2UIAgent.Builder.event("save", order: "o-1")
%{"event" => %{"name" => "save", "context" => %{"order" => "o-1"}}}

flatten(tree, options \\ [])

(since 0.1.0)
@spec flatten(tree(), keyword()) :: [map()]

Flattens tree into a list of component maps, children first.

Options:

  • :root_id — the root's id, and the prefix of the ids made for the components under it;
  • :catalog — complete and check components against this catalog (see "Catalogs" above);
  • :validate — with a catalog, whether to check components (default true);
  • :version — the protocol version whose keys bindings and function calls are written with (default: the catalog's, else "v1.0");
  • :macros — the macros (A2UIAgent.Macro) that macro calls in the tree may name.

Raises ArgumentError for a value that cannot be written as JSON and A2UICore.Error for a component the catalog rejects, or for macro calls nested deeper than 16.

messages(tree, options)

(since 0.1.0)
@spec messages(tree(), keyword()) :: [map()]

The messages that put tree on a surface: a createSurface when :catalog_id is given, an updateComponents with the flattened components, and an updateDataModel for each :data_model entry.

Options: :surface_id (required), :catalog_id, :data_model (path and value pairs, or a map), :version (the version messages state; default: the catalog's, else "v1.0"), and the options of flatten/2.

iex> import A2UIAgent.Builder.Basic
iex> A2UIAgent.Builder.messages(text(id: "root", text: "Hi"), surface_id: "s", version: "v0.9")
[
  %{
    "version" => "v0.9",
    "updateComponents" => %{
      "surfaceId" => "s",
      "components" => [%{"id" => "root", "component" => "Text", "text" => "Hi"}]
    }
  }
]

ref(id)

(since 0.1.0)
@spec ref(String.t()) :: A2UIAgent.Builder.Ref.t()

A reference to a component already on the surface, by id.