# `Drafter.Widget.Grid`
[🔗](https://github.com/jaman/drafter/blob/main/lib/drafter/widget/grid.ex#L1)

Arranges child widgets in a uniform column grid, wrapping into multiple rows.

Children are laid out left-to-right, top-to-bottom. The number of columns is
set via `:grid_size`. Column width is `floor(total_width / columns)` and row
height is divided evenly across the number of rows required. Each child widget
is mounted fresh on every render pass from its `{module, props}` tuple.

## Component tag

This module has no `component_tag/0` and no `Drafter.App` helper. It is used by
placing it in a render tree as a `{module, props}` pair, or by the renderer's
`{:grid, children, opts}` element.

## Options

  * `:children` - list of `{module, props}` tuples. Default `[]`. Each child is
    re-mounted from its props on every render pass, so a child holding its own
    state will lose it between frames
  * `:grid_size` - number of columns. Default `2`
  * `:grid_rows` - `t:pos_integer/0` or `:auto`. Default `:auto`. Carried on the
    state but not consulted: the row count is always
    `ceil(child_count / grid_size)`
  * `:padding` - Default `1`. Carried on the state but not consulted while
    rendering
  * `:style` - `t:map/0` of style properties. Default `%{}`. Carried on the state
    but not consulted while rendering

`update/2` merges the props map into the state, so every option is live.

## Widget value

`Drafter.get_widget_value/1` is not implemented for this widget and returns `nil`.

## Usage

    grid(children: [
      {Drafter.Widget.Label, %{text: "A"}},
      {Drafter.Widget.Label, %{text: "B"}},
      {Drafter.Widget.Label, %{text: "C"}},
      {Drafter.Widget.Label, %{text: "D"}}
    ], grid_size: 2)

# `child_spec`

```elixir
@type child_spec() :: {module(), Drafter.Widget.props()}
```

# `t`

```elixir
@type t() :: %{
  children: [child_spec()],
  grid_size: pos_integer(),
  grid_rows: pos_integer() | :auto,
  style: map(),
  padding: non_neg_integer()
}
```

# `handle_event`

```elixir
@spec handle_event(Drafter.Event.t(), t()) :: {:noreply, t()}
```

Ignores every event and returns `{:noreply, state}`. The grid is not focusable and
does not forward events to its children.

# `mount`

```elixir
@spec mount(Drafter.Widget.props()) :: t()
```

Builds the grid state from `props`. The state is a plain map, not a struct.

    iex> Drafter.Widget.Grid.mount(%{})
    %{children: [], grid_size: 2, grid_rows: :auto, style: %{}, padding: 1}

    iex> g = Drafter.Widget.Grid.mount(%{grid_size: 3, children: [{Drafter.Widget.Label, %{}}]})
    iex> {g.grid_size, length(g.children)}
    {3, 1}

# `render`

```elixir
@spec render(t(), Drafter.Widget.rect()) :: [Drafter.Draw.Strip.t()]
```

Renders every child into its cell and returns one strip per row of `rect.height`.

Returns `[]` when there are no children. Each cell is `div(rect.width, grid_size)`
columns wide and `div(rect.height, rows_needed)` rows tall, where `rows_needed` is
`ceil(child_count / grid_size)`; `rect.height` smaller than `rows_needed` gives a
cell height of `0` and raises `ArithmeticError`. A child strip's segments are
taken only up to the first one wider than the cell, so an over-wide segment ends
the row early rather than being cropped.

    iex> Drafter.Widget.Grid.render(Drafter.Widget.Grid.mount(%{}), %{x: 0, y: 0, width: 10, height: 2})
    []

# `update`

```elixir
@spec update(Drafter.Widget.props(), t()) :: t()
```

Merges `props` into `state`, so every option is live-updatable.

    iex> g = Drafter.Widget.Grid.mount(%{})
    iex> Drafter.Widget.Grid.update(%{grid_size: 4}, g).grid_size
    4

---

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