# `Plushie.Widget.Build`
[🔗](https://github.com/plushie-ui/plushie-elixir/blob/v0.7.2/lib/plushie/widget/build.ex#L1)

Internal helpers for widget `to_node/1` implementations.

# `animation_descriptor?`

```elixir
@spec animation_descriptor?(term()) :: boolean()
```

Returns true if the value is an animation descriptor (Transition,
Spring, or Sequence).

# `build_node`

```elixir
@spec build_node(
  opts :: keyword(),
  build_fn :: (keyword() -&gt; Plushie.Widget.ui_node())
) ::
  Plushie.Widget.ui_node()
```

Wraps a widget build pipeline with exit animation handling.

Animation descriptors (Transition, Spring, Sequence) on regular fields
go through widget setters which validate the target values. The `exit:`
prop is special (not a per-field setter), so it is extracted here and
merged onto the node's props after the build function runs.

    Build.build_node(opts, fn widget_opts ->
      Button.new(id, label, widget_opts) |> Button.build()
    end)

# `cast_color_or_passthrough`

```elixir
@spec cast_color_or_passthrough(term()) :: term()
```

Casts a color value, passing animation descriptors through unchanged.

Used by generated `to_node/1` code for Color-typed fields where struct
defaults bypass setters. Animation descriptors need to reach
Tree.normalize intact for encoding via `encode_value/1`.

# `children_to_nodes`

```elixir
@spec children_to_nodes(children :: [Plushie.Widget.child()]) :: [
  Plushie.Widget.ui_node()
]
```

Converts a list of children (ui_node maps or widget structs) to ui_node() maps.

# `put_if`

```elixir
@spec put_if(props :: map(), value :: term(), key :: atom()) :: map()
```

Adds `key => value` to props if value is not nil.

# `put_if`

```elixir
@spec put_if(
  props :: map(),
  value :: term(),
  key :: atom(),
  transform :: (term() -&gt; term())
) :: map()
```

Adds `key => transform.(value)` to props if value is not nil.

# `resolve_a11y`

```elixir
@spec resolve_a11y(props :: map()) :: map()
```

Resolves a11y derived values from the widget's props.

If the a11y prop has a `label_from` directive, the referenced prop's
value is used as the accessible label. Called during to_node after
all props are set.

# `to_node`

```elixir
@spec to_node(child :: Plushie.Widget.child()) :: Plushie.Widget.ui_node()
```

Converts a child element to a ui_node() map if it's a widget struct.

# `unknown_option!`

```elixir
@spec unknown_option!(module :: module(), key :: term()) :: no_return()
```

Raises ArgumentError for an unknown option key passed to a widget constructor.

# `validate_animation_target!`

```elixir
@spec validate_animation_target!(
  descriptor :: term(),
  field_type :: term(),
  field_name :: atom()
) :: :ok
```

Validates that an animation descriptor's `to` and `from` values are
valid for the given field type.

Called by generated animation setter clauses. Raises `ArgumentError`
if validation fails. Skips validation for `:any` typed fields.

# `validate_children_count!`

```elixir
@spec validate_children_count!(
  id :: String.t(),
  type :: String.t(),
  children :: [Plushie.Widget.child()],
  expected :: pos_integer()
) :: :ok
```

Validates that a widget has exactly the expected number of children.

Raises `ArgumentError` if the children count does not match `expected`.
The error message includes the widget type, ID, and both the expected
and actual counts:

    ** (ArgumentError) overlay "popup" requires exactly 2 children, got 1

Called at the top of `to_node/1` for widgets with strict child count
requirements (overlay).

# `validate_single_child!`

```elixir
@spec validate_single_child!(
  id :: String.t(),
  type :: String.t(),
  children :: [Plushie.Widget.child()]
) :: :ok
```

Validates that a widget has at most one child.

Raises `ArgumentError` if the children list has more than one element.
The error message includes the widget type and ID for easy diagnosis:

    ** (ArgumentError) container "sidebar" accepts at most 1 child, got 3

Called at the top of `to_node/1` for single-child wrappers (container,
tooltip, pointer_area, scrollable, themer, floating, responsive, pin,
sensor, window).

---

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