# `Macaw.Component`
[🔗](https://github.com/dcoai/macaw_component/blob/v0.1.3/lib/macaw/component.ex#L1)

The component contract (spec/01): the behavior every Macaw component implements, and
the dispatch functions a host reaches a component through.

    defmodule MyApp.Cards do
      use Macaw.Component, name: "my_app.cards", kinds: [:content]

      @impl true
      def declarations(_settings), do: {:ok, reading: :scan}

      @impl true
      def render(:content, _assigns), do: {:safe, ~s(<ul class="cards"></ul>)}
    end

**Static declarations** are `use`'s options (`name:`, `kinds:`, `hooks:`, `assets:`)
and `parameters/0`; **configured declarations** are `declarations/1`'s answer, built by
`Macaw.Component.Declarations.new/2`. The dispatch functions answer values: a
component's bad answer is an error, never a raise. A component's own raise in `render/2`
or a transition is its host's process's to take (spec/02 §6).

The contract is unstable until two implementers pass its kit (spec/00 §3).

# `fault`

```elixir
@type fault() :: {list(), term()}
```

A fault: the path to the value, and why.

# `kind`

```elixir
@type kind() :: :navigation | :content | :control | :container
```

A kind a component renders as (spec/01 §2).

# `value`

```elixir
@type value() :: term()
```

A contained component's value (spec/02 §7).

# `bound`
*optional* 

```elixir
@callback bound(value(), name :: String.t(), new :: term()) :: value()
```

# `budget`
*optional* 

```elixir
@callback budget(slot :: String.t(), settings :: map(), size :: {number(), number()}) ::
  pos_integer() | nil
```

# `declarations`

```elixir
@callback declarations(settings :: %{required(String.t()) =&gt; term()}) ::
  {:ok, keyword() | map()} | {:error, [fault()]}
```

# `delivery`
*optional* 

```elixir
@callback delivery(value(), slot :: String.t(), Macaw.Data.Delivery.t()) :: value()
```

# `init`
*optional* 

```elixir
@callback init(settings :: map(), Macaw.Component.Context.t()) :: value()
```

# `parameters`

```elixir
@callback parameters() :: %{required(String.t()) =&gt; Macaw.Data.Parameter.t()}
```

# `render`

```elixir
@callback render(kind(), assigns :: map()) :: Phoenix.HTML.Safe.t()
```

# `size`
*optional* 

```elixir
@callback size(value(), {number(), number()}) :: value()
```

# `bound`

```elixir
@spec bound(module(), value(), String.t(), term()) :: value()
```

A contained component's `bound/3` (spec/02 §7).

# `budget`

```elixir
@spec budget(module(), String.t(), map(), {number(), number()}) ::
  {:ok, pos_integer() | nil} | {:error, {:bad_budget, term()}}
```

A slot's row budget at a size: `{:ok, nil}` for a component without `budget/3`, else
`{:ok, rows}` for a positive integer or `nil`, and `{:error, {:bad_budget, answer}}`
otherwise (spec/01 §1.4).

# `component?`

```elixir
@spec component?(module()) :: boolean()
```

Whether a module is loaded and uses `Macaw.Component`.

# `contained?`

```elixir
@spec contained?(module()) :: boolean()
```

Whether a module exports every contained transition.

# `declarations`

```elixir
@spec declarations(module(), map()) ::
  {:ok, Macaw.Component.Declarations.t()} | {:error, [fault(), ...]}
```

The component's configured declarations for given settings: the settings validated, then
`declarations/1` called with every bindable parameter at its default (spec/01 §1.1), and
its answer built by `Macaw.Component.Declarations.new/2`.

# `delivery`

```elixir
@spec delivery(module(), value(), String.t(), Macaw.Data.Delivery.t()) :: value()
```

A contained component's `delivery/3` (spec/02 §7).

# `format_fault`

```elixir
@spec format_fault(fault()) :: String.t()
```

A fault as a line a person reads.

# `info`

```elixir
@spec info(module()) :: {:ok, map()} | :error
```

A component's static declarations, `%{name, kinds, hooks, assets}`, or `:error` for a
module that is not a component.

# `init`

```elixir
@spec init(module(), map(), Macaw.Component.Context.t()) :: value()
```

A contained component's `init/2` (spec/02 §7).

# `kinds`

```elixir
@spec kinds() :: [kind(), ...]
```

The kinds a component may render as, in order.

# `observations`

```elixir
@spec observations() :: [atom(), ...]
```

The closed observation vocabulary, in order (spec/01 §1.6).

# `parameters`

```elixir
@spec parameters(module()) :: {:ok, map()} | {:error, [fault(), ...]}
```

A component's parameters, each checked by `Macaw.Data.Parameter.check/1`, named by a
non-empty string, and, when bindable, with a default (spec/01 §1.1). Every fault at once,
its path from the parameter's name.

# `settings`

```elixir
@spec settings(module(), map()) :: {:ok, map()} | {:error, [fault(), ...]}
```

Given settings checked against the component's parameters, defaults filled in
(`Macaw.Data.Parameter.validate/2`).

# `size`

```elixir
@spec size(module(), value(), {number(), number()}) :: value()
```

A contained component's `size/2` (spec/02 §7).

# `transitions`

```elixir
@spec transitions() :: keyword(non_neg_integer())
```

A contained component's four transitions, as `{name, arity}`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
